Introduction
In this notebook we demonstrate how to use Milo to detect abherrant cell states in diseased tissues, using a dataset of hepatic non-parenchymal cells isolated from 5 healthy and 5 cirrhotic human livers. Ramachandran et al. 2019 (GEO accessiion: GSE136103).
Installation
Added by DRT 2021-12-03
if (!requireNamespace("BiocManager", quietly = TRUE))
install.packages("BiocManager")
bioc_pkgs <- setdiff(
c("SingleCellExperiment","scater","scran","Seurat"),
installed.packages()[,1]
)
BiocManager::install(bioc_pkgs)
'getOption("repos")' replaces Bioconductor standard repositories, see '?repositories' for details
replacement repositories:
CRAN: https://cran.rstudio.com/
Bioconductor version 3.12 (BiocManager 1.30.16), R 4.0.3 (2020-10-10)
Old packages: 'brio', 'cpp11', 'devtools', 'digest', 'dtplyr', 'fs', 'glue', 'irlba', 'pkgbuild', 'pkgload',
'readr', 'remotes', 'stringi', 'testthat', 'uwot', 'vroom', 'withr', 'xml2'
Update all/some/none? [a/s/n]:
n
getPackageIfNeeded <- function(pkg) {
if (!require(pkg, character.only=TRUE))
install.packages(pkgs=pkg, dependencies=TRUE)
}
# determine missing R libraries
pkgs <- setdiff(
c("tidyverse","miloR","patchwork","igraph",
"RColorBrewer","cowplot","devtools"),
installed.packages()[,1]
)
invisible(sapply(pkgs,getPackageIfNeeded))
if(!require(c("miloR"), character.only=TRUE)) devtools::install_github("MarioniLab/miloR")
Loading required package: miloR
Loading required package: edgeR
Loading required package: limma
# devtools::install_github("MarioniLab/miloR")
suppressPackageStartupMessages({
library(tidyverse)
# library(irlba)
# library(DropletUtils)
library(scater)
library(scran)
# library(Seurat) ## just 4 loading the object
library(miloR)
library(SingleCellExperiment)
library(patchwork)
library(igraph)
library(RColorBrewer)
library(cowplot)
})
Warning: package ‘scater’ was built under R version 4.0.4
Warning: package ‘BiocGenerics’ was built under R version 4.0.5
Warning: package ‘GenomeInfoDb’ was built under R version 4.0.5
Warning: package ‘scran’ was built under R version 4.0.5
Load data
We downloaded the dataset and annotations stored in Seurat object from here, as indicated by the authors.
# load("/nfs/team205/ed6/data/Ramachandran2019_liver/tissue.rdata")
load(url("https://www.dropbox.com/s/bq816h74gmh84gu/tissue.rdata?dl=1"))
Loading required package: Seurat
Registered S3 method overwritten by 'data.table':
method from
print.data.table
Registered S3 method overwritten by 'htmlwidgets':
method from
print.htmlwidget tools:rstudio
Registered S3 method overwritten by 'spatstat.geom':
method from
print.boxx cli
Attaching SeuratObject
Attaching package: ‘Seurat’
The following object is masked from ‘package:SummarizedExperiment’:
Assays
## Convert to SingleCellExperiment
liver_sce <- SingleCellExperiment(assay = list(counts=tissue@raw.data, logcounts=tissue@data),
colData = tissue@meta.data)
liver_sce
class: SingleCellExperiment
dim: 23498 58358
metadata(0):
assays(2): counts logcounts
rownames(23498): FO538757.2 AP006222.2 ... CTA-126B4.7 LINC01423
rowData names(0):
colnames(58358): Healthy1_Cd45+_AAACCTGCAGTATCTG Healthy1_Cd45+_AACTGGTTCATGGTCA ...
Cirrhotic3_Cd45-_TTTGTCATCCAGGGCT Cirrhotic3_Cd45-_TCTGGAAGTCATCCCT
colData names(10): nGene nUMI ... annotation_indepth annotation_lineage
reducedDimNames(0):
altExpNames(0):
Preprocessing
We use the same number of highly variable genes and principal components used by the authors of the original study.
Feature selection
Select highly variable genes
dec_liver <- modelGeneVar(liver_sce)
fit_liver <- metadata(dec_liver)
plot(fit_liver$mean, fit_liver$var, xlab="Mean of log-expression",
ylab="Variance of log-expression")

hvgs <- getTopHVGs(dec_liver, n=3000)
Dimensionality reduction
set.seed(42)
liver_sce <- runPCA(liver_sce, subset_row=hvgs, ncomponents=11)
liver_sce <- runUMAP(liver_sce, dimred="PCA", ncomponents=2)
scater::plotUMAP(liver_sce, colour_by="condition", point_alpha=1, point_size=0.5)

scater::plotUMAP(liver_sce, colour_by="dataset", point_alpha=0.3, point_size=0.5)

scater::plotUMAP(liver_sce, colour_by="annotation_lineage", point_alpha=0.3, point_size=0.5, text_by='annotation_lineage')
Warning: Removed 1 rows containing missing values (geom_text).

Notably, this dataset doesn’t appear to display a batch effect
Note: This step is not required. It generates a large file (even larger than raw data) and then reloads it.
saveRDS(liver_sce, "~/dropbox-vu/temp/milo_data/Ramachandran2019_liver/liver_SCE_20210225.RDS")
liver_sce <- readRDS(url("https://www.dropbox.com/s/z0aopf616b1urvj/liver_SCE_20210225.RDS?dl=1"))
Differential Abundance analysis with Milo
We test for differential abundance between healthy and cirrhotic livers. We start by defining neighbourhoods with refined sampling on the KNN graph. We inspect the size of neighbourhoods.
liver_milo <- Milo(liver_sce)
## Build KNN graph
liver_milo <- buildGraph(liver_milo, d = 11, k=30)
Constructing kNN graph with k:30
## Compute neighbourhoods with refined sampling
liver_milo <- makeNhoods(liver_milo, k=30, d=11, prop = 0.05, refined=TRUE)
Checking valid object
plotNhoodSizeHist(liver_milo, bins=150)

Then we make a design matrix for the differential test, assigning samples to biological conditions.
colData(liver_milo)[['sort']] <- str_remove(colData(liver_milo)[['dataset']], ".+_")
colData(liver_milo)[['sort']] <- str_remove(colData(liver_milo)[['sort']], "A|B")
liver_meta <- as_tibble(colData(liver_milo)[,c("dataset","condition", 'sort')])
liver_meta <- distinct(liver_meta) %>%
mutate(condition=factor(condition, levels=c("Uninjured", "Cirrhotic"))) %>%
column_to_rownames("dataset")
Now we can count cells in neighbourhoods and perform the DA test.
liver_milo <- countCells(liver_milo, samples = "dataset", meta.data = data.frame(colData(liver_milo)[,c("dataset","condition",'sort')]) )
Checking meta.data validity
Counting cells in neighbourhoods
liver_milo <- calcNhoodDistance(liver_milo, d=11)
milo_res <- testNhoods(liver_milo, design = ~ condition, design.df = liver_meta[colnames(nhoodCounts(liver_milo)),])
Using TMM normalisation
Performing spatial FDR correction withk-distance weighting
milo_res_sort <- testNhoods(liver_milo, design = ~ sort + condition, design.df =
liver_meta[colnames(nhoodCounts(liver_milo)),])
Using TMM normalisation
Performing spatial FDR correction withk-distance weighting
compare_da_df <- left_join(milo_res_sort, milo_res, by="Nhood", suffix=c("_sort", "_nosort")) %>%
{annotateNhoods(liver_milo, ., 'annotation_lineage')}
compare_da_df %>%
ggplot(aes(-log10(SpatialFDR_sort), -log10(SpatialFDR_nosort))) +
geom_point(size=0.8) +
geom_point(data=. %>% filter(annotation_lineage=="Endothelia"), color="red")

plot(milo_res_sort$SpatialFDR, milo_res$SpatialFDR)

Exploration of Milo DA results
We can start by looking at some basic stats
pval_hist <- milo_res %>%
ggplot(aes(PValue)) +
geom_histogram(bins=50) +
theme_bw(base_size=14)
volcano <-
milo_res %>%
ggplot(aes(logFC, -log10(SpatialFDR))) +
geom_point(size=0.4, alpha=0.2) +
geom_hline(yintercept = -log10(0.1)) +
xlab("log-Fold Change") +
theme_bw(base_size=14)
pval_hist + volcano

The distribution of P-values looks sensible and from the volcano plot we can see that we have identified some DA neighbourhoods at 10% FDR.
We can visualize DA neighbourhoods building an abstracted graph
liver_milo <- buildNhoodGraph(liver_milo)
plotNhoodGraphDA(liver_milo, milo_res, alpha = 0.1, size_range=c(2,6))

Note: This step is not required. It generates a large file (even larger than raw data) and then reloads it.
## Save milo object and results
saveRDS(liver_milo,"~/dropbox-vu/temp/milo_data/Ramachandran2019_liver/liver_milo_20210225.RDS")
write_csv(milo_res,"~/dropbox-vu/temp/milo_data/Ramachandran2019_liver/liver_results_20210225.csv")
# liver_milo <- readRDS("~/liver_milo_20201008.RDS")
liver_milo <- readRDS(url("https://www.dropbox.com/s/xdp07789c5hoen3/liver_milo_20210225.RDS?dl=1"))
# milo_res <- read_csv("/nfs/team205/ed6/data/Ramachandran2019_liver/liver_results_20201008.csv")
milo_res <- read_csv(url("https://www.dropbox.com/s/i1l3aep1py5wirf/liver_results_20210225.csv?dl=1"))
NOTE: hvgs (presumably highly variable genes) cannot be loaded since file not provided
## Load hvgs
hvgs <- scan("~/data/Ramachandran2019_liver/liver_milo_hvgs.txt", "")
Warning in file(file, "r") :
cannot open file '/Users/darren/data/Ramachandran2019_liver/liver_milo_hvgs.txt': No such file or directory
Error in file(file, "r") : cannot open the connection
Attempting to generate a set of highly variable genes
Making figures for the manuscript
Explore DA neighbourhoods by cell type
Next, we can check the cell types where we observe most differences between healthy and cirrhotic cells, by taking the most frequent cell type in each neighbourhood.
We first check that neighbourhoods are sufficiently homogeneous
Filter nhoods with homogeneous composition
I can recover all the clusters where DA was detected in the original paper
Close-up on Endothelial lineage
Close-up on Cholangiocytes
Filter out cells that show contamination from immune cells (expression of immune markers)
Differential Gene Expression analysis
In a subset of lineages, we want to test for differential expression between neighbourhoods enriched in cirrhotic cells and neighbourhoods enriched
NOTE: Code below here won’t work unless hvgs is defined
DRT: stopping run-through here
Should be able to run everything above.
Add nhood expression to speed-up plotting of heatmaps
liver_milo <- calcNhoodExpression(liver_milo, assay = "logcounts", subset.row = hvgs)
Endothelia
Rebuttal figure showcasing grouping
set.seed(42)
milo_res_endogroups <- groupNhoods(liver_milo, milo_res, max.lfc.delta = 2, overlap = 1)
p1 <- plotNhoodGroups(liver_milo, milo_res_endogroups,
size_range=c(1,3))
milo_res_endogroups <- annotateNhoods(liver_milo, milo_res_endogroups, 'annotation_lineage')
p2 <- plotDAbeeswarm(milo_res_endogroups, group.by = 'NhoodGroup') +
facet_grid(annotation_lineage~., scales="free", space="free")
## Plot expression in T cell neighbourhoods
markers_df <- read_csv("~/mount/gdrive/milo/STable3_Ramachandran.csv")
tcell_marker_genes <-
markers_df %>%
filter(cluster %in% c("Tcell", "ILC")) %>%
top_n(30, myAUC) %>%
pull(gene)
p3 <- plotNhoodExpressionGroups(liver_milo, milo_res_endogroups, features = unique(tcell_marker_genes),
subset.nhoods = milo_res_endogroups$NhoodGroup %in% c("3","10", "14"),
scale=TRUE, cluster_features = TRUE,show_rownames = TRUE
) +
theme(strip.text.x = element_text(angle=90))
(((p1 + theme())/ (p3 + theme(strip.text = element_text(size=10, angle=45)))) +
plot_layout(heights = c(1.1,1), guides="collect"
)|
(
p2 + theme_bw(base_size=16) + theme(strip.text.y = element_text(angle=0))
)) +
plot_layout(widths = c(1.4, 1)) +
plot_annotation(tag_levels = c("A", "C", "B") ) +
ggsave("~/mount/gdrive/milo/Figures/liver_v2/RFig_grouping.pdf", width=15, height = 12) +
ggsave("~/mount/gdrive/milo/Figures/liver_v2/RFig_grouping.png", width=15, height = 12)
Group endothelial cells by logFC and DA results
milo_res_endogroups$annotation_indepth[milo_res_endogroups$annotation_indepth_fraction < 0.6] <- NA
milo_res_endogroups$annotation_lineage[milo_res_endogroups$annotation_indepth_fraction < 0.6] <- NA
## Group neighbourhoods by DA outcome
milo_res_endogroups$NhoodGroup <- NA
milo_res_endogroups$NhoodGroup <- ifelse((milo_res_endogroups$annotation_lineage == "Endothelia") & (milo_res_endogroups$SpatialFDR < 0.1) & (milo_res_endogroups$logFC < -2.5), "54", milo_res_endogroups$NhoodGroup)
milo_res_endogroups$NhoodGroup <- ifelse((milo_res_endogroups$annotation_lineage == "Endothelia") & (milo_res_endogroups$SpatialFDR < 0.1) & (milo_res_endogroups$logFC > 2.5), "70", milo_res_endogroups$NhoodGroup)
liver_milo2 <- liver_milo
subset.nhoods <- str_detect(milo_res$annotation_indepth, "Endo")
reducedDim(liver_milo2, "UMAP")[colnames(endo_milo),] <- reducedDim(endo_milo, "UMAP")
endo_gr_groups <- plotNhoodGroups(liver_milo2, milo_res_endogroups[milo_res_endogroups$annotation_lineage=="Endothelia",],
show_groups = c("54", "70"),
size_range=c(1,4),
subset.nhoods = milo_res_endogroups$annotation_lineage=="Endothelia") +
scale_fill_manual(values=c("54"=brewer.pal(4, "Spectral")[2], "70"=brewer.pal(4, "Spectral")[3]),
labels=c("54"="Uninjured group", '70'= "Cirrhotic group"),
na.value="white",
name = "Nhood group"
) +
theme(legend.text = element_text(size=20), legend.title = element_text(size=22))
fig4_bright1 <- ((endo_umap + endo_gr) +
plot_layout(widths = c(1,2), guides="collect"
)) &
theme(legend.box = "horizontal", legend.position = "top", legend.direction = "vertical")
fig4_bright1
Calculate marker genes between the two groups
mito_genes <- str_detect(hvgs, "^MT-")
markers_df <- findNhoodGroupMarkers(liver_milo, da.res = milo_res_endogroups, assay="counts",
subset.nhoods = (milo_res_endogroups$NhoodGroup %in% c("54", "70")),
subset.groups = c("54", "70"),
subset.row = hvgs[!mito_genes],
aggregate.samples = TRUE, sample_col = "dataset"
)
milo_res_endogroups[milo_res_endogroups$NhoodGroup %in% c("54", "70"),]
colnames(markers_df) <- str_replace(colnames(markers_df), "70", "cirr")
colnames(markers_df) <- str_replace(colnames(markers_df), "54", "uninj")
Visualize as volcano
highlight_genes <- c("PLVAP", "VWA1", "ACKR1", "IL32",
"CLEC4G", "CLEC4M", "FCN2", "FCN3",
"LEF1")
marker.df <- markers_df
marker.df %>%
mutate(label=ifelse(GeneID %in% highlight_genes, GeneID, NA)) %>%
ggplot(aes(logFC_cirr, -log10(adj.P.Val_cirr),
# color=highlight
)) +
geom_point() +
geom_text(aes(label=label), color="red") +
xlab("logFC") + ylab("- log10(Adj. P value)") +
theme_bw(base_size = 22)
Visualize as heatmap
(gene expression values are scaled between 0 and 1 for each gene)
marker_genes <- marker.df %>%
dplyr::filter(adj.P.Val_cirr < 0.05) %>%
pull(GeneID)
fig4_bbright <-
plotNhoodExpressionDA(liver_milo, milo_res_endogroups, c(marker_genes), cluster_features = TRUE, assay = "counts",
alpha = 0.1,
scale_to_1 = TRUE,
subset.nhoods = milo_res_endogroups$NhoodGroup %in% c("54", "70"),
# grid.space = "free",
highlight_features = highlight_genes, show_rownames = FALSE
) +
ylab("DE genes")+
# facet_grid(.~NhoodGroup, scales="free", space="free")
theme(legend.text = element_text(size=22), legend.title = element_text(size=24)) +
plot_layout(heights = c(1,10)) & theme(legend.margin = margin(0,0,0,60), legend.background = element_blank())
pl3 <- fig4_bbright$data %>%
ggplot(aes(logFC_rank, 1,fill=logFC)) +
geom_tile() +
theme_classic(base_size=16) +
ylab("") +
scale_fill_gradient2(name="DA logFC") +
# scale_fill_manual(values=c("54"=brewer.pal(4, "Spectral")[2], "70"=brewer.pal(4, "Spectral")[3]),
# labels=c("54"="Uninjured group", '70'= "Cirrhotic group"),
# na.value="white",
# name = "Nhood group"
# ) +
scale_x_continuous(expand = c(0.01, 0)) +
theme(axis.text = element_blank(), axis.ticks = element_blank(), axis.line = element_blank(),
axis.title = element_blank())
fig4_bbright <- pl3 / fig4_bbright +
plot_layout(heights = c(1,20))
fig4_bbright
GO term analysis
go_endo_up <- em_res_up %>%
top_n(30, -log10(qvalue)) %>%
mutate(ID=ifelse(ID=='GO_ANTIGEN_PROCESSING_AND_PRESENTATION_OF_PEPTIDE_OR_POLYSACCHARIDE_ANTIGEN_VIA_MHC_CLASS_II', "GO_ANTIGEN_PRESENTATION_VIA_MHC_CLASS_II", ID)) %>%
mutate(Term=factor(ID, levels=rev(unique(ID)))) %>%
ggplot(aes(Term, -log10(qvalue))) +
geom_point() +
coord_flip() +
xlab("GO Biological Function") + ylab("-log10(Adj. p-value)") +
theme_bw(base_size=18) +
ggtitle("Cirrhotic endothelia")
go_endo_down <- em_res_down %>%
top_n(30, -log10(qvalue)) %>%
mutate(ID=ifelse(ID=='GO_ANTIGEN_PROCESSING_AND_PRESENTATION_OF_PEPTIDE_OR_POLYSACCHARIDE_ANTIGEN_VIA_MHC_CLASS_II', "GO_ANTIGEN_PRESENTATION_VIA_MHC_CLASS_II", ID)) %>%
mutate(Term=factor(ID, levels=rev(unique(ID)))) %>%
ggplot(aes(Term, -log10(qvalue))) +
geom_point() +
coord_flip() +
xlab("GO Biological Function") + ylab("-log10(Adj. p-value)") +
theme_bw(base_size=18) +
ggtitle("Uninjured endothelia")
go_endo_up
go_endo_down
em_res_up
em_res_down
Cholangiocytes
set.seed(42)
milo_res_cholgroups <- groupNhoods(liver_milo, milo_res, max.lfc.delta = 0.5, overlap = 1)
## Group neighbourhoods by DA outcome
milo_res_cholgroups$NhoodGroup <- NA
milo_res_cholgroups$NhoodGroup <- ifelse((milo_res_cholgroups$annotation_lineage == "Cholangiocytes") & (milo_res_cholgroups$SpatialFDR < 0.1) & (milo_res_cholgroups$logFC < -2.5), "38", milo_res_cholgroups$NhoodGroup)
milo_res_cholgroups$NhoodGroup <- ifelse((milo_res_cholgroups$annotation_lineage == "Cholangiocytes") & (milo_res_cholgroups$SpatialFDR < 0.1) & (milo_res_cholgroups$logFC > 2.5), "49", milo_res_cholgroups$NhoodGroup)
liver_milo2 <- liver_milo
subset.nhoods <- str_detect(milo_res$annotation_indepth, "Chol")
reducedDim(liver_milo2, "UMAP")[colnames(chol_milo),] <- reducedDim(chol_milo, "UMAP")
plotNhoodGroups(liver_milo2, milo_res_cholgroups[milo_res_cholgroups$annotation_lineage=="Cholangiocytes",],
show_groups = c("49","38"),
subset.nhoods = milo_res_cholgroups$annotation_lineage =="Cholangiocytes")
Calculate marker genes between the two groups
## Filter genes expressed in cholangiocytes
# chol_hvgs <- hvgs[(counts(chol_milo)[hvgs,] > 0) %>% {rowSums(.)/ncol(chol_milo)} > 0.01]
mito_genes <- str_detect(hvgs, "^MT-")
markers_df <- findNhoodGroupMarkers(liver_milo, da.res = milo_res_cholgroups, assay="counts",
subset.nhoods = milo_res_cholgroups$NhoodGroup %in%c("49","38"),
subset.groups = c("49","38"),
subset.row = hvgs[!mito_genes],
aggregate.samples = TRUE, sample_col = "dataset"
)
markers_df
milo_res_cholgroups[milo_res_cholgroups$NhoodGroup %in%c("49","38"),]
Visualize as volcano
marker.df.chol <- markers_df
volcano_chol <-
marker.df.chol %>%
mutate(up=ifelse(logFC_49 > 0, "up", "down")) %>%
group_by(up) %>%
mutate(label=ifelse(rank(adj.P.Val_49) < 15, GeneID, NA)) %>%
# mutate(label=ifelse((adj.P.Val_49 < 0.05 & logFC_49 < -3) | (adj.P.Val_49 < 0.05 & logFC_49 > 0), GeneID, NA)) %>%
ggplot(aes(logFC_49, -log10(adj.P.Val_49),
# color=highlight
)) +
geom_point(size=0.8, alpha=0.6) +
ggrepel::geom_text_repel(aes(label=label), segment.alpha = 0.2) +
xlab("logFC") + ylab("- log10(Adj. P value)") +
theme_bw(base_size = 22)
volcano_chol
GO term analysis
go_chol_up <- em_res_up_chol %>%
top_n(20, -log10(qvalue)) %>%
mutate(Term=factor(ID, levels=rev(unique(ID)))) %>%
ggplot(aes(Term, -log10(qvalue))) +
geom_point() +
coord_flip() +
xlab("GO Biological Function") + ylab("-log10(Adj. p-value)") +
theme_bw(base_size=18) +
ggtitle("Cirrhotic cholangiocytes")
go_chol_up
em_res_up_chol
Assemble figure
fig4_bottom <- ((fig4_bleft + plot_layout()) |
((fig4_bright1 + plot_layout(tag_level = 'keep')) / (fig4_bbright + plot_layout())) +
plot_layout(heights = c(1,1.6))
) +
plot_layout(widths=c(1,1.4))
(fig4_top / fig4_bottom) +
plot_layout(heights=c(1,1.8)) +
ggsave("~/mount/gdrive/milo/Figures/liver_v2/fig4_raw.pdf", height = 26, width = 24, useDingbats=FALSE)
# ggsave("~/mount/gdrive/milo/Figures/liver_v2/fig4_raw.png", height = 26, width = 24, useDingbats=FALSE)
# ggsave("~/milo/ms/figures/figs/figure5.pdf", height = 26, width = 22, useDingbats=FALSE)
Assemble supplementary figure
p1 <- plot_grid( go_endo_up+ theme(plot.title = element_text(hjust = 1),
axis.title.x = element_text(hjust = 1)),
go_endo_down+ theme(plot.title = element_text(hjust = 1),
axis.title.x = element_text(hjust = 1)),
label_size = 18,
ncol=1,
rel_heights = c(2,2),
labels = c("A", "B","C"))
p1
chol_emb <- (chol_umap + chol_gr ) +
plot_layout(widths = c(1,2),
guides = "collect"
)
plot_grid(
go_endo_up+ theme(plot.title = element_text(hjust = 1),
axis.title.x = element_text(hjust = 1)),
go_endo_down+ theme(plot.title = element_text(hjust = 1),
axis.title.x = element_text(hjust = 1)),
label_size = 18,
ncol=1,
rel_heights = c(2,2), rel_widths = c(2,2),
labels = c("A", "B")
) +
ggsave("~/mount/gdrive/milo/Figures/liver_v2/suppl_fig_endo.pdf", height = 12, width=12) +
ggsave("~/mount/gdrive/milo/Figures/liver_v2/suppl_fig_endo.png", height = 12, width=12)
plot_grid(plot_grid(chol_umap, chol_gr, volcano_chol, nrow=1,rel_widths = c(1,2,2),
label_size = 18,
labels = c("A","B","C")),
go_chol_up + theme(plot.title = element_text(hjust = 1),
axis.title.x = element_text(hjust = 1)),
ncol=1,
rel_heights = c(1,1),
label_size = 18,
labels=c("",'D')) +
ggsave("~/mount/gdrive/milo/Figures/liver_v2/suppl_fig7.pdf", height = 13, width=14) +
ggsave("~/mount/gdrive/milo/Figures/liver_v2/suppl_fig7.png", height = 13, width=14)
LS0tCnRpdGxlOiAiTWlsbzogbGl2ZXIgY2lycmhvc2lzIGFuYWx5c2lzIgpvdXRwdXQ6IAogIGh0bWxfbm90ZWJvb2s6CiAgICBjb2RlX2ZvbGRpbmc6IGhpZGUKLS0tCgojIyBJbnRyb2R1Y3Rpb24KCkluIHRoaXMgbm90ZWJvb2sgd2UgZGVtb25zdHJhdGUgaG93IHRvIHVzZSBNaWxvIHRvIGRldGVjdCBhYmhlcnJhbnQgY2VsbCBzdGF0ZXMgaW4gZGlzZWFzZWQgdGlzc3VlcywgdXNpbmcgYSBkYXRhc2V0IG9mIGhlcGF0aWMgbm9uLXBhcmVuY2h5bWFsIGNlbGxzIGlzb2xhdGVkIGZyb20gNSBoZWFsdGh5IGFuZCA1IGNpcnJob3RpYyBodW1hbiBsaXZlcnMuIFtSYW1hY2hhbmRyYW4gZXQgYWwuIDIwMTldKGh0dHBzOi8vd3d3Lm5hdHVyZS5jb20vYXJ0aWNsZXMvczQxNTg2LTAxOS0xNjMxLTMjU2VjMSkgKEdFTyBhY2Nlc3NpaW9uOiBHU0UxMzYxMDMpLgoKIyMgSW5zdGFsbGF0aW9uCiMjIyMgQWRkZWQgYnkgRFJUIDIwMjEtMTItMDMKCmBgYHtyIEluc3RhbGxhdGlvbn0KaWYgKCFyZXF1aXJlTmFtZXNwYWNlKCJCaW9jTWFuYWdlciIsIHF1aWV0bHkgPSBUUlVFKSkKICAgIGluc3RhbGwucGFja2FnZXMoIkJpb2NNYW5hZ2VyIikKCmJpb2NfcGtncyA8LSBzZXRkaWZmKAogICAgICAgICAgICBjKCJTaW5nbGVDZWxsRXhwZXJpbWVudCIsInNjYXRlciIsInNjcmFuIiwiU2V1cmF0IiksCiAgICAgICAgICAgIGluc3RhbGxlZC5wYWNrYWdlcygpWywxXQogICAgICAgICkKCkJpb2NNYW5hZ2VyOjppbnN0YWxsKGJpb2NfcGtncykKCmdldFBhY2thZ2VJZk5lZWRlZCA8LSBmdW5jdGlvbihwa2cpIHsKICBpZiAoIXJlcXVpcmUocGtnLCBjaGFyYWN0ZXIub25seT1UUlVFKSkKICAgIGluc3RhbGwucGFja2FnZXMocGtncz1wa2csIGRlcGVuZGVuY2llcz1UUlVFKQp9CgojIGRldGVybWluZSBtaXNzaW5nIFIgbGlicmFyaWVzCnBrZ3MgPC0gc2V0ZGlmZigKICAgICAgICAgICAgYygidGlkeXZlcnNlIiwibWlsb1IiLCJwYXRjaHdvcmsiLCJpZ3JhcGgiLAogICAgICAgICAgICAgICJSQ29sb3JCcmV3ZXIiLCJjb3dwbG90IiwiZGV2dG9vbHMiKSwKICAgICAgICAgICAgaW5zdGFsbGVkLnBhY2thZ2VzKClbLDFdCiAgICAgICAgKQoKaW52aXNpYmxlKHNhcHBseShwa2dzLGdldFBhY2thZ2VJZk5lZWRlZCkpCgppZighcmVxdWlyZShjKCJtaWxvUiIpLCBjaGFyYWN0ZXIub25seT1UUlVFKSkgZGV2dG9vbHM6Omluc3RhbGxfZ2l0aHViKCJNYXJpb25pTGFiL21pbG9SIikKYGBgCgoKYGBge3J9CiMgZGV2dG9vbHM6Omluc3RhbGxfZ2l0aHViKCJNYXJpb25pTGFiL21pbG9SIikKc3VwcHJlc3NQYWNrYWdlU3RhcnR1cE1lc3NhZ2VzKHsKICBsaWJyYXJ5KHRpZHl2ZXJzZSkKICAjIGxpYnJhcnkoaXJsYmEpCiAgIyBsaWJyYXJ5KERyb3BsZXRVdGlscykKICBsaWJyYXJ5KHNjYXRlcikKICBsaWJyYXJ5KHNjcmFuKQogICMgbGlicmFyeShTZXVyYXQpICMjIGp1c3QgNCBsb2FkaW5nIHRoZSBvYmplY3QKICBsaWJyYXJ5KG1pbG9SKQogIGxpYnJhcnkoU2luZ2xlQ2VsbEV4cGVyaW1lbnQpCiAgbGlicmFyeShwYXRjaHdvcmspCiAgbGlicmFyeShpZ3JhcGgpCiAgbGlicmFyeShSQ29sb3JCcmV3ZXIpCiAgbGlicmFyeShjb3dwbG90KQogIH0pCmBgYAoKIyMgTG9hZCBkYXRhCgpXZSBkb3dubG9hZGVkIHRoZSBkYXRhc2V0IGFuZCBhbm5vdGF0aW9ucyBzdG9yZWQgaW4gU2V1cmF0IG9iamVjdCBmcm9tIFtoZXJlXShodHRwczovL2RhdGFzaGFyZS5pcy5lZC5hYy51ay9oYW5kbGUvMTAyODMvMzQzMyksIGFzIGluZGljYXRlZCBieSB0aGUgYXV0aG9ycy4KCmBgYHtyfQojIGxvYWQoIi9uZnMvdGVhbTIwNS9lZDYvZGF0YS9SYW1hY2hhbmRyYW4yMDE5X2xpdmVyL3Rpc3N1ZS5yZGF0YSIpCmxvYWQodXJsKCJodHRwczovL3d3dy5kcm9wYm94LmNvbS9zL2JxODE2aDc0Z21oODRndS90aXNzdWUucmRhdGE/ZGw9MSIpKQojIyBDb252ZXJ0IHRvIFNpbmdsZUNlbGxFeHBlcmltZW50CmxpdmVyX3NjZSA8LSBTaW5nbGVDZWxsRXhwZXJpbWVudChhc3NheSA9IGxpc3QoY291bnRzPXRpc3N1ZUByYXcuZGF0YSwgbG9nY291bnRzPXRpc3N1ZUBkYXRhKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbERhdGEgPSB0aXNzdWVAbWV0YS5kYXRhKQoKbGl2ZXJfc2NlCmBgYAoKIyMgUHJlcHJvY2Vzc2luZwoKV2UgdXNlIHRoZSBzYW1lIG51bWJlciBvZiBoaWdobHkgdmFyaWFibGUgZ2VuZXMgYW5kIHByaW5jaXBhbCBjb21wb25lbnRzIHVzZWQgYnkgdGhlIGF1dGhvcnMgb2YgdGhlIG9yaWdpbmFsIHN0dWR5LiAKCiMjIyBGZWF0dXJlIHNlbGVjdGlvbgoKU2VsZWN0IGhpZ2hseSB2YXJpYWJsZSBnZW5lcwoKYGBge3J9CmRlY19saXZlciA8LSBtb2RlbEdlbmVWYXIobGl2ZXJfc2NlKQoKZml0X2xpdmVyIDwtIG1ldGFkYXRhKGRlY19saXZlcikKcGxvdChmaXRfbGl2ZXIkbWVhbiwgZml0X2xpdmVyJHZhciwgeGxhYj0iTWVhbiBvZiBsb2ctZXhwcmVzc2lvbiIsCiAgICB5bGFiPSJWYXJpYW5jZSBvZiBsb2ctZXhwcmVzc2lvbiIpCgpodmdzIDwtIGdldFRvcEhWR3MoZGVjX2xpdmVyLCBuPTMwMDApCmBgYAoKIyMjIERpbWVuc2lvbmFsaXR5IHJlZHVjdGlvbgoKYGBge3IsIGZpZy5oZWlnaHQ9OCwgZmlnLndpZHRoPTh9CnNldC5zZWVkKDQyKQpsaXZlcl9zY2UgPC0gcnVuUENBKGxpdmVyX3NjZSwgc3Vic2V0X3Jvdz1odmdzLCBuY29tcG9uZW50cz0xMSkKbGl2ZXJfc2NlIDwtIHJ1blVNQVAobGl2ZXJfc2NlLCBkaW1yZWQ9IlBDQSIsIG5jb21wb25lbnRzPTIpCgpzY2F0ZXI6OnBsb3RVTUFQKGxpdmVyX3NjZSwgY29sb3VyX2J5PSJjb25kaXRpb24iLCBwb2ludF9hbHBoYT0xLCAgcG9pbnRfc2l6ZT0wLjUpCnNjYXRlcjo6cGxvdFVNQVAobGl2ZXJfc2NlLCBjb2xvdXJfYnk9ImRhdGFzZXQiLCBwb2ludF9hbHBoYT0wLjMsICBwb2ludF9zaXplPTAuNSkKc2NhdGVyOjpwbG90VU1BUChsaXZlcl9zY2UsIGNvbG91cl9ieT0iYW5ub3RhdGlvbl9saW5lYWdlIiwgcG9pbnRfYWxwaGE9MC4zLCAgcG9pbnRfc2l6ZT0wLjUsIHRleHRfYnk9J2Fubm90YXRpb25fbGluZWFnZScpCmBgYAoKTm90YWJseSwgdGhpcyBkYXRhc2V0IGRvZXNuJ3QgYXBwZWFyIHRvIGRpc3BsYXkgYSBiYXRjaCBlZmZlY3QKCiMjIyBOb3RlOiBUaGlzIHN0ZXAgaXMgbm90IHJlcXVpcmVkLiBJdCBnZW5lcmF0ZXMgYSBsYXJnZSBmaWxlIChldmVuIGxhcmdlciB0aGFuIHJhdyBkYXRhKSBhbmQgdGhlbiByZWxvYWRzIGl0LiAKYGBge3Igc2F2ZS1sb2FkIGludGVybWVkIGZpbGUgMSwgZXZhbD1GQUxTRSwgaW5jbHVkZT1UUlVFLCBlY2hvPVRSVUV9CnNhdmVSRFMobGl2ZXJfc2NlLCAifi9kcm9wYm94LXZ1L3RlbXAvbWlsb19kYXRhL1JhbWFjaGFuZHJhbjIwMTlfbGl2ZXIvbGl2ZXJfU0NFXzIwMjEwMjI1LlJEUyIpCmxpdmVyX3NjZSA8LSByZWFkUkRTKHVybCgiaHR0cHM6Ly93d3cuZHJvcGJveC5jb20vcy96MGFvcGY2MTZiMXVydmovbGl2ZXJfU0NFXzIwMjEwMjI1LlJEUz9kbD0xIikpCmBgYAoKIyMgRGlmZmVyZW50aWFsIEFidW5kYW5jZSBhbmFseXNpcyB3aXRoIE1pbG8KCldlIHRlc3QgZm9yIGRpZmZlcmVudGlhbCBhYnVuZGFuY2UgYmV0d2VlbiBoZWFsdGh5IGFuZCBjaXJyaG90aWMgbGl2ZXJzLiBXZSBzdGFydCBieSBkZWZpbmluZyBuZWlnaGJvdXJob29kcyB3aXRoIHJlZmluZWQgc2FtcGxpbmcgb24gdGhlIEtOTiBncmFwaC4gV2UgaW5zcGVjdCB0aGUgc2l6ZSBvZiBuZWlnaGJvdXJob29kcy4KCmBgYHtyfQpsaXZlcl9taWxvIDwtIE1pbG8obGl2ZXJfc2NlKQoKIyMgQnVpbGQgS05OIGdyYXBoCmxpdmVyX21pbG8gPC0gYnVpbGRHcmFwaChsaXZlcl9taWxvLCBkID0gMTEsIGs9MzApCgojIyBDb21wdXRlIG5laWdoYm91cmhvb2RzIHdpdGggcmVmaW5lZCBzYW1wbGluZwpsaXZlcl9taWxvIDwtIG1ha2VOaG9vZHMobGl2ZXJfbWlsbywgaz0zMCwgZD0xMSwgcHJvcCA9IDAuMDUsIHJlZmluZWQ9VFJVRSkKcGxvdE5ob29kU2l6ZUhpc3QobGl2ZXJfbWlsbywgYmlucz0xNTApCmBgYAoKVGhlbiB3ZSBtYWtlIGEgZGVzaWduIG1hdHJpeCBmb3IgdGhlIGRpZmZlcmVudGlhbCB0ZXN0LCBhc3NpZ25pbmcgc2FtcGxlcyB0byBiaW9sb2dpY2FsIGNvbmRpdGlvbnMuCgpgYGB7cn0KY29sRGF0YShsaXZlcl9taWxvKVtbJ3NvcnQnXV0gPC0gc3RyX3JlbW92ZShjb2xEYXRhKGxpdmVyX21pbG8pW1snZGF0YXNldCddXSwgIi4rXyIpCmNvbERhdGEobGl2ZXJfbWlsbylbWydzb3J0J11dIDwtIHN0cl9yZW1vdmUoY29sRGF0YShsaXZlcl9taWxvKVtbJ3NvcnQnXV0sICJBfEIiKQoKbGl2ZXJfbWV0YSA8LSBhc190aWJibGUoY29sRGF0YShsaXZlcl9taWxvKVssYygiZGF0YXNldCIsImNvbmRpdGlvbiIsICdzb3J0JyldKQpsaXZlcl9tZXRhIDwtIGRpc3RpbmN0KGxpdmVyX21ldGEpICU+JQogIG11dGF0ZShjb25kaXRpb249ZmFjdG9yKGNvbmRpdGlvbiwgbGV2ZWxzPWMoIlVuaW5qdXJlZCIsICJDaXJyaG90aWMiKSkpICU+JQogIGNvbHVtbl90b19yb3duYW1lcygiZGF0YXNldCIpCgpgYGAKCk5vdyB3ZSBjYW4gY291bnQgY2VsbHMgaW4gbmVpZ2hib3VyaG9vZHMgYW5kIHBlcmZvcm0gdGhlIERBIHRlc3QuCgpgYGB7cn0KbGl2ZXJfbWlsbyA8LSBjb3VudENlbGxzKGxpdmVyX21pbG8sIHNhbXBsZXMgPSAiZGF0YXNldCIsIG1ldGEuZGF0YSA9IGRhdGEuZnJhbWUoY29sRGF0YShsaXZlcl9taWxvKVssYygiZGF0YXNldCIsImNvbmRpdGlvbiIsJ3NvcnQnKV0pICkKbGl2ZXJfbWlsbyA8LSBjYWxjTmhvb2REaXN0YW5jZShsaXZlcl9taWxvLCBkPTExKQptaWxvX3JlcyA8LSB0ZXN0Tmhvb2RzKGxpdmVyX21pbG8sIGRlc2lnbiA9IH4gY29uZGl0aW9uLCBkZXNpZ24uZGYgPSBsaXZlcl9tZXRhW2NvbG5hbWVzKG5ob29kQ291bnRzKGxpdmVyX21pbG8pKSxdKQptaWxvX3Jlc19zb3J0IDwtIHRlc3ROaG9vZHMobGl2ZXJfbWlsbywgZGVzaWduID0gfiBzb3J0ICsgY29uZGl0aW9uLCBkZXNpZ24uZGYgPSAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsaXZlcl9tZXRhW2NvbG5hbWVzKG5ob29kQ291bnRzKGxpdmVyX21pbG8pKSxdKQpgYGAKCmBgYHtyfQpjb21wYXJlX2RhX2RmIDwtIGxlZnRfam9pbihtaWxvX3Jlc19zb3J0LCBtaWxvX3JlcywgYnk9Ik5ob29kIiwgc3VmZml4PWMoIl9zb3J0IiwgIl9ub3NvcnQiKSkgJT4lCiAge2Fubm90YXRlTmhvb2RzKGxpdmVyX21pbG8sIC4sICdhbm5vdGF0aW9uX2xpbmVhZ2UnKX0gCgpjb21wYXJlX2RhX2RmICU+JQogIGdncGxvdChhZXMoLWxvZzEwKFNwYXRpYWxGRFJfc29ydCksIC1sb2cxMChTcGF0aWFsRkRSX25vc29ydCkpKSArCiAgZ2VvbV9wb2ludChzaXplPTAuOCkgKwogIGdlb21fcG9pbnQoZGF0YT0uICU+JSBmaWx0ZXIoYW5ub3RhdGlvbl9saW5lYWdlPT0iRW5kb3RoZWxpYSIpLCBjb2xvcj0icmVkIikKcGxvdChtaWxvX3Jlc19zb3J0JFNwYXRpYWxGRFIsIG1pbG9fcmVzJFNwYXRpYWxGRFIpCmBgYAoKCiMjIEV4cGxvcmF0aW9uIG9mIE1pbG8gREEgcmVzdWx0cwoKV2UgY2FuIHN0YXJ0IGJ5IGxvb2tpbmcgYXQgc29tZSBiYXNpYyBzdGF0cwoKYGBge3J9CnB2YWxfaGlzdCA8LSBtaWxvX3JlcyAlPiUKICBnZ3Bsb3QoYWVzKFBWYWx1ZSkpICsKICBnZW9tX2hpc3RvZ3JhbShiaW5zPTUwKSArCiAgdGhlbWVfYncoYmFzZV9zaXplPTE0KQoKdm9sY2FubyA8LQogIG1pbG9fcmVzICU+JQogIGdncGxvdChhZXMobG9nRkMsIC1sb2cxMChTcGF0aWFsRkRSKSkpICsKICBnZW9tX3BvaW50KHNpemU9MC40LCBhbHBoYT0wLjIpICsKICBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAtbG9nMTAoMC4xKSkgKwogIHhsYWIoImxvZy1Gb2xkIENoYW5nZSIpICsKICB0aGVtZV9idyhiYXNlX3NpemU9MTQpCgpwdmFsX2hpc3QgKyB2b2xjYW5vCmBgYAoKVGhlIGRpc3RyaWJ1dGlvbiBvZiBQLXZhbHVlcyBsb29rcyBzZW5zaWJsZSBhbmQgZnJvbSB0aGUgdm9sY2FubyBwbG90IHdlIGNhbiBzZWUgdGhhdCB3ZSBoYXZlIGlkZW50aWZpZWQgc29tZSBEQSBuZWlnaGJvdXJob29kcyBhdCAxMCUgRkRSLgoKV2UgY2FuIHZpc3VhbGl6ZSBEQSBuZWlnaGJvdXJob29kcyBidWlsZGluZyBhbiBhYnN0cmFjdGVkIGdyYXBoCgpgYGB7ciwgZmlnLndpZHRoPTE0LCBmaWcuaGVpZ2h0PTEwfQpsaXZlcl9taWxvIDwtIGJ1aWxkTmhvb2RHcmFwaChsaXZlcl9taWxvKQpwbG90Tmhvb2RHcmFwaERBKGxpdmVyX21pbG8sIG1pbG9fcmVzLCBhbHBoYSA9IDAuMSwgc2l6ZV9yYW5nZT1jKDIsNikpCmBgYAoKIyMjIE5vdGU6IFRoaXMgc3RlcCBpcyBub3QgcmVxdWlyZWQuIEl0IGdlbmVyYXRlcyBhIGxhcmdlIGZpbGUgKGV2ZW4gbGFyZ2VyIHRoYW4gcmF3IGRhdGEpIGFuZCB0aGVuIHJlbG9hZHMgaXQuIApgYGB7ciBzYXZlIGludGVybWVkIGZpbGVzIDIsIGV2YWw9RkFMU0UsIGluY2x1ZGU9VFJVRSwgZWNobz1UUlVFfQojIyBTYXZlIG1pbG8gb2JqZWN0IGFuZCByZXN1bHRzCnNhdmVSRFMobGl2ZXJfbWlsbywifi9kcm9wYm94LXZ1L3RlbXAvbWlsb19kYXRhL1JhbWFjaGFuZHJhbjIwMTlfbGl2ZXIvbGl2ZXJfbWlsb18yMDIxMDIyNS5SRFMiKQp3cml0ZV9jc3YobWlsb19yZXMsIn4vZHJvcGJveC12dS90ZW1wL21pbG9fZGF0YS9SYW1hY2hhbmRyYW4yMDE5X2xpdmVyL2xpdmVyX3Jlc3VsdHNfMjAyMTAyMjUuY3N2IikKCmBgYApgYGB7ciBsb2FkIGludGVybWVkIGZpbGVzIDIsIGV2YWw9RkFMU0UsIGluY2x1ZGU9VFJVRSwgZWNobz1UUlVFfQojIGxpdmVyX21pbG8gPC0gcmVhZFJEUygifi9saXZlcl9taWxvXzIwMjAxMDA4LlJEUyIpCmxpdmVyX21pbG8gPC0gcmVhZFJEUyh1cmwoImh0dHBzOi8vd3d3LmRyb3Bib3guY29tL3MveGRwMDc3ODljNWhvZW4zL2xpdmVyX21pbG9fMjAyMTAyMjUuUkRTP2RsPTEiKSkKIyBtaWxvX3JlcyA8LSByZWFkX2NzdigiL25mcy90ZWFtMjA1L2VkNi9kYXRhL1JhbWFjaGFuZHJhbjIwMTlfbGl2ZXIvbGl2ZXJfcmVzdWx0c18yMDIwMTAwOC5jc3YiKQptaWxvX3JlcyA8LSByZWFkX2Nzdih1cmwoImh0dHBzOi8vd3d3LmRyb3Bib3guY29tL3MvaTFsM2FlcDFweTV3aXJmL2xpdmVyX3Jlc3VsdHNfMjAyMTAyMjUuY3N2P2RsPTEiKSkKYGBgCgojIyMgTk9URTogYGh2Z3NgIChwcmVzdW1hYmx5IGhpZ2hseSB2YXJpYWJsZSBnZW5lcykgY2Fubm90IGJlIGxvYWRlZCBzaW5jZSBmaWxlIG5vdCBwcm92aWRlZApgYGB7cn0KIyMgTG9hZCBodmdzIApodmdzIDwtIHNjYW4oIn4vZGF0YS9SYW1hY2hhbmRyYW4yMDE5X2xpdmVyL2xpdmVyX21pbG9faHZncy50eHQiLCAiIikKYGBgCgojIyMgQXR0ZW1wdGluZyB0byBnZW5lcmF0ZSBhIHNldCBvZiBoaWdobHkgdmFyaWFibGUgZ2VuZXMKYGBge3J9CiMKYGBgCgpNYWtpbmcgZmlndXJlcyBmb3IgdGhlIG1hbnVzY3JpcHQKCmBgYHtyLCBmaWcud2lkdGg9MTUsIGZpZy5oZWlnaHQ9MTB9CmxpYnJhcnkoZ2dyYXN0cikKY29sb3VyQ291bnQgPSBsZW5ndGgodW5pcXVlKGxpdmVyX21pbG8kYW5ub3RhdGlvbl9saW5lYWdlKSkKZ2V0UGFsZXR0ZSA9IGNvbG9yUmFtcFBhbGV0dGUoYnJld2VyLnBhbCg5LCAiU2V0MiIpKQoKdW1hcF9kZiA8LSBkYXRhLmZyYW1lKHJlZHVjZWREaW0obGl2ZXJfbWlsbywgIlVNQVAiKSkKY29sbmFtZXModW1hcF9kZikgPC0gYygiVU1BUF8xIiwgIlVNQVBfMiIpCgp1bWFwMSA8LSBjYmluZCh1bWFwX2RmLCBhbm5vdGF0aW9uX2xpbmVhZ2U9bGl2ZXJfbWlsbyRhbm5vdGF0aW9uX2xpbmVhZ2UpICU+JQogIGdncGxvdChhZXMoVU1BUF8xLCBVTUFQXzIsIGNvbG9yPWFzLmNoYXJhY3Rlcihhbm5vdGF0aW9uX2xpbmVhZ2UpKSkgKwogIGdlb21fcG9pbnRfcmFzdChzaXplPTAuMSwgYWxwaGE9MC41LCByYXN0ZXIuZHBpID0gODAwKSArCiAgZ2dyZXBlbDo6Z2VvbV90ZXh0X3JlcGVsKGRhdGEgPSAuICU+JQogICAgICAgICAgICAgIGdyb3VwX2J5KGFubm90YXRpb25fbGluZWFnZSkgJT4lCiAgICAgICAgICAgICAgc3VtbWFyaXNlKFVNQVBfMT1tZWFuKFVNQVBfMSksIFVNQVBfMj1tZWFuKFVNQVBfMikpLAogICAgICAgICAgICBhZXMobGFiZWw9YW5ub3RhdGlvbl9saW5lYWdlKSwgY29sb3I9ImJsYWNrIiwgc2l6ZT02CiAgICAgICAgICAgICkgKwogIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXM9Z2V0UGFsZXR0ZShjb2xvdXJDb3VudCkpICsKICBndWlkZXMoY29sb3I9Im5vbmUiKSArCiAgeGxhYigiVU1BUDEiKSArIHlsYWIoIlVNQVAyIikgKwogIGNvb3JkX2ZpeGVkKCkgKwogIHRoZW1lX2NsYXNzaWMoYmFzZV9zaXplID0gMjIpICsKICB0aGVtZShheGlzLnRleHQgPSBlbGVtZW50X2JsYW5rKCksIGF4aXMudGlja3MgPSBlbGVtZW50X2JsYW5rKCkpCgp1bWFwMiA8LQogIGNiaW5kKHVtYXBfZGYsIGNvbmRpdGlvbj1hcy5jaGFyYWN0ZXIobGl2ZXJfbWlsbyRjb25kaXRpb24pKSAlPiUKICBnZ3Bsb3QoYWVzKFVNQVBfMSwgVU1BUF8yLCBjb2xvcj1jb25kaXRpb24pKSArCiAgZ2VvbV9wb2ludF9yYXN0KHNpemU9MC4xLCBhbHBoYT0wLjUsIHJhc3Rlci5kcGkgPSA4MDApICsKICBzY2FsZV9jb2xvcl9icmV3ZXIocGFsZXR0ZT0iU2V0MSIsIG5hbWU9JycpICsKICB4bGFiKCJVTUFQMSIpICsgeWxhYigiVU1BUDIiKSArCiAgY29vcmRfZml4ZWQoKSArCiAgZ3VpZGVzKGNvbG9yPSdub25lJykgKwogIGZhY2V0X3dyYXAoY29uZGl0aW9ufi4sIG5jb2w9MSkgKwogIHRoZW1lX25vdGhpbmcoZm9udF9zaXplID0gMjIpICsKICB0aGVtZShheGlzLnRleHQgPSBlbGVtZW50X2JsYW5rKCksIGF4aXMudGlja3MgPSBlbGVtZW50X2JsYW5rKCksIGxlZ2VuZC5wb3NpdGlvbj1jKDAuOSwwLjkpLAogICAgICAgIHN0cmlwLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoY29sb3I9TkEpLCBzdHJpcC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemU9MjIpKQoKbmhfZ3JhcGhfcGwgPC0gcGxvdE5ob29kR3JhcGhEQShsaXZlcl9taWxvLCBtaWxvX3JlcywgYWxwaGEgPSAwLjEsIHNpemVfcmFuZ2U9YygxLDQpKSArCiAgdGhlbWUobGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZT0yMCksIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplPTIyKSkgKwogIGNvb3JkX2ZpeGVkKCkKCiMgbmhfZ3JhcGhfcGwgKyBnZ3NhdmUoIn4vbW91bnQvZ2RyaXZlL21pbG8vRmlndXJlcy9saXZlcl92Mi9saXZlcl9ncmFwaC5wZGYiLCBoZWlnaHQgPSA3LCB3aWR0aCA9IDgpCmdnc2F2ZSgifi9kcm9wYm94LXZ1L3RlbXAvbWlsb19vdXRwdXQvbGl2ZXJfdjIvbGl2ZXJfZ3JhcGgucGRmIiwgaGVpZ2h0ID0gNywgd2lkdGggPSA4KQoKZmlnNF90b3AgPC0gKHVtYXAxIHwgdW1hcDIgfCBuaF9ncmFwaF9wbCkgKwogIHBsb3RfbGF5b3V0KHdpZHRocyA9IGMoMywxLDMpKQoKZmlnNF90b3AKYGBgCgojIyMgRXhwbG9yZSBEQSBuZWlnaGJvdXJob29kcyBieSBjZWxsIHR5cGUKCk5leHQsIHdlIGNhbiBjaGVjayB0aGUgY2VsbCB0eXBlcyB3aGVyZSB3ZSBvYnNlcnZlIG1vc3QgZGlmZmVyZW5jZXMgYmV0d2VlbiBoZWFsdGh5IGFuZCBjaXJyaG90aWMgY2VsbHMsIGJ5IHRha2luZyB0aGUgbW9zdCBmcmVxdWVudCBjZWxsIHR5cGUgaW4gZWFjaCBuZWlnaGJvdXJob29kLgoKYGBge3IsIGZpZy53aWR0aD05LCBmaWcuaGVpZ2h0PTEwfQptaWxvX3JlcyA8LSBtaWxvX3Jlc1ssIXN0cl9kZXRlY3QoY29sbmFtZXMobWlsb19yZXMpLCAiYW5ub3RhdGlvbl9saW5lYWdlIildCgojIEFkZCBhbm5vdGF0aW9uIG9mIG1vc3QgZnJlcXVlbnQgY2VsbCB0eXBlIHBlciBuaG9vZCB0byBtaWxvIHJlc3VsdHMgdGFibGUKbWlsb19yZXMgPC0gYW5ub3RhdGVOaG9vZHMobGl2ZXJfbWlsbywgbWlsb19yZXMsICJhbm5vdGF0aW9uX2luZGVwdGgiKQphbm5vX2RmIDwtIGRhdGEuZnJhbWUobGl2ZXJfbWlsb0Bjb2xEYXRhKSAlPiUKICBkaXN0aW5jdChhbm5vdGF0aW9uX2xpbmVhZ2UsIGFubm90YXRpb25faW5kZXB0aCkKbWlsb19yZXMgPC0gbGVmdF9qb2luKG1pbG9fcmVzLCBhbm5vX2RmLCBieT0iYW5ub3RhdGlvbl9pbmRlcHRoIikKYGBgCgpXZSBmaXJzdCBjaGVjayB0aGF0IG5laWdoYm91cmhvb2RzIGFyZSBzdWZmaWNpZW50bHkgaG9tb2dlbmVvdXMKCmBgYHtyfQpmcmFjX2hpc3QgPC0gZ2dwbG90KG1pbG9fcmVzLCBhZXMoYW5ub3RhdGlvbl9pbmRlcHRoX2ZyYWN0aW9uKSkgKwogIGdlb21faGlzdG9ncmFtKGJpbnM9MzApICsKICB4bGFiKCJGcmFjdGlvbiBvZiBjZWxscyBpbiBcbm1vc3QgYWJ1bmRhbnQgY2x1c3RlciIpICsKICB5bGFiKCIjIG5laWdoYm91cmhvb2RzIikgKwogIHRoZW1lX2J3KGJhc2Vfc2l6ZT0xNCkKCmZyYWNfaGlzdApgYGAKCkZpbHRlciBuaG9vZHMgd2l0aCBob21vZ2VuZW91cyBjb21wb3NpdGlvbgoKYGBge3J9Cm1pbG9fcmVzJGFubm90YXRpb25faW5kZXB0aFttaWxvX3JlcyRhbm5vdGF0aW9uX2luZGVwdGhfZnJhY3Rpb24gPCAwLjZdIDwtIE5BCm1pbG9fcmVzJGFubm90YXRpb25fbGluZWFnZVttaWxvX3JlcyRhbm5vdGF0aW9uX2luZGVwdGhfZnJhY3Rpb24gPCAwLjZdIDwtIE5BCmBgYAoKCkkgY2FuIHJlY292ZXIgYWxsIHRoZSBjbHVzdGVycyB3aGVyZSBEQSB3YXMgZGV0ZWN0ZWQgaW4gdGhlIG9yaWdpbmFsIHBhcGVyCgpgYGB7ciwgZmlnLndpZHRoPTEwLCBmaWcuaGVpZ2h0PTEwLCB3YXJuaW5nPUZBTFNFLCBtZXNzYWdlPUZBTFNFfQpncm91cC5ieSA9ICJhbm5vdGF0aW9uX2luZGVwdGgiCnBhcGVyX0RBIDwtIGxpc3QoY2lycmhvdGljPWMoIk1QcyAoNCkiLCJNUHMgKDUpIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiRW5kb3RoZWxpYSAoNikiLCAiRW5kb3RoZWxpYSAoNykiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICJNZXMgKDMpIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiVGNlbGxzICgyKSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIk15b2ZpYnJvYmxhc3RzIgogICAgICAgICAgICAgICAgICAgICAgICAgICAgICksCiAgICAgICAgICAgICAgICAgaGVhbHRoeT1jKCJNUHMgKDcpIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIkVuZG90aGVsaWEgKDEpIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgIlRjZWxscyAoMSkiLCAiVGNlbGxzICgzKSIsIlRjZWxscyAoMSkiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAiSUxDcyAoMSkiCiAgICAgICAgICAgICAgICAgICAgICAgICAgICkKICAgICAgICAgICAgICAgICApCgpleHBEQV9kZiA8LSBiaW5kX3Jvd3MoCiAgZGF0YS5mcmFtZShhbm5vdGF0aW9uX2luZGVwdGggPSBwYXBlcl9EQVtbImNpcnJob3RpYyJdXSwgcHJlZF9EQT0iY2lycmhvdGljIiksCiAgZGF0YS5mcmFtZShhbm5vdGF0aW9uX2luZGVwdGggPSBwYXBlcl9EQVtbImhlYWx0aHkiXV0sIHByZWRfREE9ImhlYWx0aHkiKQogICkKCnBsMSA8LSBtaWxvX3JlcyAlPiUKICBsZWZ0X2pvaW4oZXhwREFfZGYpICU+JQogIG11dGF0ZShpc19zaWduaWYgPSBpZmVsc2UoU3BhdGlhbEZEUiA8IDAuMSwgMSwgMCkpICU+JQogIG11dGF0ZShsb2dGQ19jb2xvciA9IGlmZWxzZShpc19zaWduaWY9PTEsIGxvZ0ZDLCBOQSkpICU+JQogIGFycmFuZ2UoYW5ub3RhdGlvbl9saW5lYWdlKSAlPiUKICBtdXRhdGUoTmhvb2Q9ZmFjdG9yKE5ob29kLCBsZXZlbHM9dW5pcXVlKE5ob29kKSkpICU+JQogIGZpbHRlcighaXMubmEoYW5ub3RhdGlvbl9saW5lYWdlKSkgJT4lCiAgZ2dwbG90KGFlcyhhbm5vdGF0aW9uX2luZGVwdGgsIGxvZ0ZDLCBjb2xvcj1sb2dGQ19jb2xvcikpICsKICBzY2FsZV9jb2xvcl9ncmFkaWVudDIoKSArCiAgZ3VpZGVzKGNvbG9yPSJub25lIikgKwogIHhsYWIoZ3JvdXAuYnkpICsgeWxhYigiTG9nIEZvbGQgQ2hhbmdlIikgKwogIGdnYmVlc3dhcm06Omdlb21fcXVhc2lyYW5kb20oYWxwaGE9MSkgKwogIGNvb3JkX2ZsaXAoKSArCiAgZmFjZXRfZ3JpZChhbm5vdGF0aW9uX2xpbmVhZ2V+Liwgc2NhbGVzPSJmcmVlIiwgc3BhY2U9ImZyZWUiKSArCiAgdGhlbWVfYncoYmFzZV9zaXplPTIyKSArCiAgdGhlbWUoc3RyaXAudGV4dC55ID0gIGVsZW1lbnRfdGV4dChhbmdsZT0wKSwKICAgICAgICBheGlzLnRpdGxlLnkgPSBlbGVtZW50X2JsYW5rKCksIGF4aXMudGV4dC55ID0gZWxlbWVudF9ibGFuaygpLCBheGlzLnRpY2tzLnkgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgKQoKcGwyIDwtIG1pbG9fcmVzICU+JQogIGxlZnRfam9pbihleHBEQV9kZikgJT4lCiAgIyBkcGx5cjo6ZmlsdGVyKCFpcy5uYShwcmVkX0RBKSkgJT4lCiAgZ3JvdXBfYnkoYW5ub3RhdGlvbl9pbmRlcHRoKSAlPiUKICBzdW1tYXJpc2UocHJlZF9EQT1kcGx5cjo6Zmlyc3QocHJlZF9EQSksIGFubm90YXRpb25fbGluZWFnZT1kcGx5cjo6Zmlyc3QoYW5ub3RhdGlvbl9saW5lYWdlKSkgJT4lCiAgbXV0YXRlKGVuZD1pZmVsc2UocHJlZF9EQT09ImhlYWx0aHkiLCAwLCAxKSwKICAgICAgICAgc3RhcnQ9aWZlbHNlKHByZWRfREE9PSJoZWFsdGh5IiwgMSwgMCkpICU+JQogIGZpbHRlcighaXMubmEoYW5ub3RhdGlvbl9saW5lYWdlKSkgJT4lCiAgZ2dwbG90KGFlcyhhbm5vdGF0aW9uX2luZGVwdGgsIHN0YXJ0LCB4ZW5kID0gYW5ub3RhdGlvbl9pbmRlcHRoLCB5ZW5kID0gZW5kLCBjb2xvcj1wcmVkX0RBKSkgKwogIGdlb21fc2VnbWVudChzaXplPTEsYXJyb3c9YXJyb3cobGVuZ3RoID0gdW5pdCgwLjEsICJucGMiKSwgdHlwZT0iY2xvc2VkIikpICsKICBjb29yZF9mbGlwKCkgKwogIHhsYWIoImFubm90YXRpb24iKSArCiAgZmFjZXRfZ3JpZChhbm5vdGF0aW9uX2xpbmVhZ2V+LiwKICAgICMgYW5ub3RhdGlvbl9saW5lYWdlfiJSYW1hY2hhbmRyYW4gZXQgYWwuXG5EQSBwcmVkaWN0aW9ucyIsCiAgICAgICAgICAgICBzY2FsZXM9ImZyZWUiLCBzcGFjZT0iZnJlZSIpICsKICAjIGd1aWRlcyhjb2xvcj0ibm9uZSIpICsKICBzY2FsZV9jb2xvcl9icmV3ZXIocGFsZXR0ZT0iU2V0MSIsIGRpcmVjdGlvbiA9IC0xLAogICAgICAgICAgICAgICAgICAgICBsYWJlbHM9YygiZW5yaWNoZWQgaW4gY2lycmhvdGljIiwgImVucmljaGVkIGluIGhlYWx0aHkiKSwKICAgICAgICAgICAgICAgICAgICAgbmEudHJhbnNsYXRlID0gRiwKICAgICAgICAgICAgICAgICAgICAgbmFtZT0iUmFtYWNoYW5kcmFuIGV0IGFsLlxuREEgcHJlZGljdGlvbnMiKSArCiAgZ3VpZGVzKGNvbG9yPWd1aWRlX2xlZ2VuZChuY29sID0gMSkpICsKICB0aGVtZV9idyhiYXNlX3NpemU9MjIpICsKICB5bGltKC0wLjEsMS4xKSArCiAgdGhlbWUoc3RyaXAudGV4dC55ID0gZWxlbWVudF9ibGFuaygpLHN0cmlwLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZT05MCksCiAgICAgICAgcGxvdC5tYXJnaW4gPSB1bml0KGMoMCwwLDAsMCksICJjbSIpLCBwYW5lbC5ncmlkID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIGF4aXMudGl0bGUueCA9IGVsZW1lbnRfYmxhbmsoKSwgYXhpcy50ZXh0LnggPSBlbGVtZW50X2JsYW5rKCksIGF4aXMudGlja3MueCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIikKCmZpZzRfYmxlZnQgPC0gKHBsMiArIHBsMSArCiAgcGxvdF9sYXlvdXQod2lkdGhzPWMoMSwxMCksIGd1aWRlcyA9ICJjb2xsZWN0IikgJiB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAndG9wJywgbGVnZW5kLmp1c3RpZmljYXRpb24gPSAwKSkKCiMgZ2dzYXZlKCJ+L21vdW50L2dkcml2ZS9taWxvL0ZpZ3VyZXMvbGl2ZXJfdjIvbGl2ZXJfREFjb21wYXJpc29uLnBkZiIsIHdpZHRoPTgsIGhlaWdodCA9IDEzKQpnZ3NhdmUoIn4vZHJvcGJveC12dS90ZW1wL21pbG9fb3V0cHV0L2xpdmVyX3YyL2xpdmVyX0RBY29tcGFyaXNvbi5wZGYiLCB3aWR0aD04LCBoZWlnaHQgPSAxMykKYGBgCgojIyMgQ2xvc2UtdXAgb24gRW5kb3RoZWxpYWwgbGluZWFnZQoKYGBge3J9CmVuZG9fbWlsbyA8LSBzY2F0ZXI6OnJ1blVNQVAobGl2ZXJfbWlsb1ssbGl2ZXJfbWlsbyRhbm5vdGF0aW9uX2xpbmVhZ2U9PSJFbmRvdGhlbGlhIl0sICBkaW1yZWQ9J1BDQScpCnBsb3RVTUFQKGVuZG9fbWlsbywgY29sb3VyX2J5ID0gImFubm90YXRpb25faW5kZXB0aCIpCmBgYAoKYGBge3J9CnVtYXBfZGYgPC0gZGF0YS5mcmFtZShyZWR1Y2VkRGltKGVuZG9fbWlsbywgIlVNQVAiKSkKY29sbmFtZXModW1hcF9kZikgPC0gYygiVU1BUF8xIiwgIlVNQVBfMiIpCgplbmRvX3VtYXAgPC0gY2JpbmQodW1hcF9kZiwgY29uZGl0aW9uPWVuZG9fbWlsbyRjb25kaXRpb24pICU+JQogICBnZ3Bsb3QoYWVzKFVNQVBfMSwgVU1BUF8yLCBjb2xvcj1jb25kaXRpb24pKSArCiAgZ2VvbV9wb2ludChzaXplPTAuMywgYWxwaGE9MC41KSArCiAgc2NhbGVfY29sb3JfYnJld2VyKHBhbGV0dGU9IlNldDEiLCBuYW1lPScnKSArCiAgeGxhYigiVU1BUDEiKSArIHlsYWIoIlVNQVAyIikgKwogIGNvb3JkX2ZpeGVkKCkgKwogIGd1aWRlcyhjb2xvcj0ibm9uZSIpICsKICBmYWNldF93cmFwKGNvbmRpdGlvbn4uLCBuY29sPTEpICsKICB0aGVtZV9ub3RoaW5nKCkgKwogIHRoZW1lKGF4aXMudGV4dCA9IGVsZW1lbnRfYmxhbmsoKSwgYXhpcy50aWNrcyA9IGVsZW1lbnRfYmxhbmsoKSwgbGVnZW5kLnBvc2l0aW9uPWMoMC45LDAuOSksCiAgICAgICAgc3RyaXAuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChjb2xvcj1OQSksIHN0cmlwLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZT0yMikpCmBgYAoKYGBge3IsIGZpZy53aWR0aD04LCBmaWcuaGVpZ2h0PTQsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CmxpdmVyX21pbG8yIDwtIGxpdmVyX21pbG8Kc3Vic2V0Lm5ob29kcyA8LSBzdHJfZGV0ZWN0KG1pbG9fcmVzJGFubm90YXRpb25faW5kZXB0aCwgIkVuZG8iKQpyZWR1Y2VkRGltKGxpdmVyX21pbG8yLCAiVU1BUCIpW2NvbG5hbWVzKGVuZG9fbWlsbyksXSA8LSByZWR1Y2VkRGltKGVuZG9fbWlsbywgIlVNQVAiKSAKCmVuZG9fZ3IgPC0KICBwbG90Tmhvb2RHcmFwaERBKAogIGxpdmVyX21pbG8yLCBtaWxvX3JlcywKICBzdWJzZXQubmhvb2RzID0gd2hpY2gobWlsb19yZXMkYW5ub3RhdGlvbl9saW5lYWdlID09ICJFbmRvdGhlbGlhIiksIAogIHNpemVfcmFuZ2U9YygxLDQpLAogICMgKSA9KVsxOihsZW5ndGgoKS0xKV0sIAogIGFscGhhID0gMC4xCiAgKSAgKwogICB0aGVtZShsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplPTIwKSwgbGVnZW5kLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemU9MjIpKQogIAojIGxpdmVyX21pbG8yIDwtIGxpdmVyX21pbG8KIyBzdWJzZXQubmhvb2RzIDwtIHN0cl9kZXRlY3QobWlsb19yZXMkYW5ub3RhdGlvbl9pbmRlcHRoLCAiRW5kbyIpCiMgcmVkdWNlZERpbShsaXZlcl9taWxvMiwgIlVNQVAiKVtjb2xuYW1lcyhlbmRvX21pbG8pLF0gPC0gcmVkdWNlZERpbShlbmRvX21pbG8sICJVTUFQIikgCiMgZW5kb19ncl9ncm91cHMgPC0gcGxvdE5ob29kR3JvdXBzKGxpdmVyX21pbG8yLCBtaWxvX3Jlc19lbmRvZ3JvdXBzW21pbG9fcmVzX2VuZG9ncm91cHMkYW5ub3RhdGlvbl9saW5lYWdlPT0iRW5kb3RoZWxpYSIsXSwgCiMgICAgICAgICAgICAgICAgIHNob3dfZ3JvdXBzID0gYygiNTQiLCAiNzAiKSwKIyAgICAgICAgICAgICAgICAgc2l6ZV9yYW5nZT1jKDEsNCksCiMgICAgICAgICAgICAgICAgIHN1YnNldC5uaG9vZHMgPSBtaWxvX3Jlc19lbmRvZ3JvdXBzJGFubm90YXRpb25fbGluZWFnZT09IkVuZG90aGVsaWEiKSArCiMgICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXM9YygiNTQiPWJyZXdlci5wYWwoNCwgIlNwZWN0cmFsIilbMl0sICI3MCI9YnJld2VyLnBhbCg0LCAiU3BlY3RyYWwiKVszXSksIAojICAgICAgICAgICAgICAgICAgICAgbGFiZWxzPWMoIjU0Ij0iVW5pbmp1cmVkIGdyb3VwIiwgJzcwJz0gIkNpcnJob3RpYyBncm91cCIpLAojICAgICAgICAgICAgICAgICAgICAgbmEudmFsdWU9IndoaXRlIiwKIyAgICAgICAgICAgICAgICAgICAgIG5hbWUgPSAiTmhvb2QgZ3JvdXAiCiMgICAgICAgICAgICAgICAgICAgICApICsKIyAgIHRoZW1lKGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemU9MjApLCBsZWdlbmQudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZT0yMikpCgpmaWc0X2JyaWdodDEgPC0gKChlbmRvX3VtYXAgKyBlbmRvX2dyICkgKyAKICBwbG90X2xheW91dCh3aWR0aHMgPSBjKDEsMiksIAogICAgICAgICAgICAgICAgZ3VpZGVzID0gImNvbGxlY3QiCiAgICAgICAgICAgICAgICApKSAKZmlnNF9icmlnaHQxCmBgYAoKPCEtLSBgYGB7cn0gLS0+CjwhLS0gbmhfZ3JhcGggPC0gbmhvb2RHcmFwaChsaXZlcl9taWxvKVtzdWJzZXQubmhvb2RzLHN1YnNldC5uaG9vZHNdIC0tPgo8IS0tIG5oX2dyYXBoIDwtIGdyYXBoX2Zyb21fYWRqYWNlbmN5X21hdHJpeChuaF9ncmFwaCkgLS0+Cgo8IS0tIGNvbF92YWxzIDwtIGNvbERhdGEobGl2ZXJfbWlsbylbYXMubnVtZXJpYyh2ZXJ0ZXhfYXR0cihuaF9ncmFwaCkkbmFtZSksIGNvbG91cl9ieV0gLS0+CjwhLS0gVihuaF9ncmFwaCkkY29sb3VyX2J5IDwtIGlmZWxzZShtaWxvX3Jlc1tzdWJzZXQubmhvb2RzLCJTcGF0aWFsRkRSIl0gPiAwLjEsIDAsIG1pbG9fcmVzW3N1YnNldC5uaG9vZHMsImxvZ0ZDIl0pIC0tPgo8IS0tIGdncmFwaChzaW1wbGlmeShuaF9ncmFwaCkpICsgLS0+CjwhLS0gICAgICAgZ2VvbV9lZGdlX2xpbmswKGVkZ2VfY29sb3VyID0gImdyZXk2NiIsIGVkZ2VfYWxwaGE9MC4yKSAgICsgLS0+CjwhLS0gICAgICAgZ2VvbV9ub2RlX3BvaW50KGFlcyhmaWxsID0gY29sb3VyX2J5KSwgc2hhcGU9MjEsIHNpemU9MikgKyAtLT4KPCEtLSAgIHNjYWxlX2ZpbGxfZ3JhZGllbnQyKCkgLS0+CjwhLS0gYGBgIC0tPgoKCiMjIyBDbG9zZS11cCBvbiBDaG9sYW5naW9jeXRlcwoKYGBge3J9CmNob2xfbWlsbyA8LSBzY2F0ZXI6OnJ1blVNQVAobGl2ZXJfbWlsb1ssbGl2ZXJfbWlsbyRhbm5vdGF0aW9uX2xpbmVhZ2U9PSJDaG9sYW5naW9jeXRlcyJdLCAgZGltcmVkPSdQQ0EnKQpwbG90VU1BUChjaG9sX21pbG8sIGNvbG91cl9ieSA9ICJhbm5vdGF0aW9uX2luZGVwdGgiKQoKcGxvdFVNQVAoY2hvbF9taWxvLCBjb2xvdXJfYnkgPSAicGVyY2VudC5taXRvIikKYGBgCgpGaWx0ZXIgb3V0IGNlbGxzIHRoYXQgc2hvdyBjb250YW1pbmF0aW9uIGZyb20gaW1tdW5lIGNlbGxzIChleHByZXNzaW9uIG9mIGltbXVuZSBtYXJrZXJzKQoKYGBge3J9CmtlZXAgPC0gbG9nY291bnRzKGNob2xfbWlsbylbIkNEMTkiLF0gPT0gMCB8IGxvZ2NvdW50cyhjaG9sX21pbG8pWyJNUzRBMSIsXSA9PSAwCmNob2xfbWlsbyA8LSBjaG9sX21pbG9bLGtlZXBdCmNob2xfbWlsbyA8LSBzY2F0ZXI6OnJ1blVNQVAoY2hvbF9taWxvLCAgZGltcmVkPSdQQ0EnKQoKcGxvdFVNQVAoY2hvbF9taWxvLCBjb2xvdXJfYnkgPSAiYW5ub3RhdGlvbl9pbmRlcHRoIikKYGBgCgpgYGB7ciwgZmlnLndpZHRoPTEwLCBmaWcuaGVpZ2h0PTh9CnVtYXBfZGYgPC0gZGF0YS5mcmFtZShyZWR1Y2VkRGltKGNob2xfbWlsbywgIlVNQVAiKSkKY29sbmFtZXModW1hcF9kZikgPC0gYygiVU1BUF8xIiwgIlVNQVBfMiIpCgpjaG9sX3VtYXAgPC0gY2JpbmQodW1hcF9kZiwgY29uZGl0aW9uPWNob2xfbWlsbyRjb25kaXRpb24pICU+JQogICBnZ3Bsb3QoYWVzKFVNQVBfMSwgVU1BUF8yLCBjb2xvcj1jb25kaXRpb24pKSArCiAgZ2VvbV9wb2ludChzaXplPTAuMywgYWxwaGE9MC41KSArCiAgc2NhbGVfY29sb3JfYnJld2VyKHBhbGV0dGU9IlNldDEiLCBuYW1lPScnKSArCiAgeGxhYigiVU1BUDEiKSArIHlsYWIoIlVNQVAyIikgKwogIGNvb3JkX2ZpeGVkKCkgKwogIGd1aWRlcyhjb2xvcj0ibm9uZSIpICsKICBmYWNldF93cmFwKGNvbmRpdGlvbn4uLCBuY29sPTEpICsKICB0aGVtZV9ub3RoaW5nKCkgKwogIHRoZW1lKGF4aXMudGV4dCA9IGVsZW1lbnRfYmxhbmsoKSwgYXhpcy50aWNrcyA9IGVsZW1lbnRfYmxhbmsoKSwgbGVnZW5kLnBvc2l0aW9uPWMoMC45LDAuOSksCiAgICAgICAgc3RyaXAuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChjb2xvcj1OQSksIHN0cmlwLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZT0yMikpCgpjaG9sX3VtYXAKYGBgCgpgYGB7ciwgZmlnLndpZHRoPTgsIGZpZy5oZWlnaHQ9NCwgd2FybmluZz1GQUxTRSwgbWVzc2FnZT1GQUxTRX0KbGl2ZXJfbWlsbzIgPC0gbGl2ZXJfbWlsbwpzdWJzZXQubmhvb2RzIDwtIG1pbG9fcmVzJGFubm90YXRpb25fbGluZWFnZT09IkNob2xhbmdpb2N5dGVzIgpyZWR1Y2VkRGltKGxpdmVyX21pbG8yLCAiVU1BUCIpW2NvbG5hbWVzKGNob2xfbWlsbyksXSA8LSByZWR1Y2VkRGltKGNob2xfbWlsbywgIlVNQVAiKSAKCmNob2xfZ3IgPC0KICBwbG90Tmhvb2RHcmFwaERBKAogIGxpdmVyX21pbG8yLCBtaWxvX3JlcywKICBzdWJzZXQubmhvb2RzID0gc3Vic2V0Lm5ob29kcywKICBzaXplX3JhbmdlPWMoMiw1KSwKICAjICkgPSlbMToobGVuZ3RoKCktMSldLCAKICBhbHBoYSA9IDAuMQogICkgICsKICAgdGhlbWUobGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZT0yMiksIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplPTI0KSkKICAKKGNob2xfdW1hcCArIGNob2xfZ3IgKSArIAogIHBsb3RfbGF5b3V0KHdpZHRocyA9IGMoMSwyKSwgCiAgICAgICAgICAgICAgICBndWlkZXMgPSAiY29sbGVjdCIKICAgICAgICAgICAgICAgICkKIyBmaWc0X2JyaWdodDEgKwojICAgZ2dzYXZlKCJ+L21pbG9fb3V0cHV0L2xpdmVyX2VuZG9HcmFwaC5wZGYiLCB3aWR0aD05LCBoZWlnaHQgPSA1KSAgCmdnc2F2ZSgifi9kcm9wYm94LXZ1L3RlbXAvbWlsb19vdXRwdXQvbGl2ZXJfZW5kb0dyYXBoLnBkZiIsIHdpZHRoPTksIGhlaWdodCA9IDUpICAKYGBgCgojIyMgRGlmZmVyZW50aWFsIEdlbmUgRXhwcmVzc2lvbiBhbmFseXNpcwoKSW4gYSBzdWJzZXQgb2YgbGluZWFnZXMsIHdlIHdhbnQgdG8gdGVzdCBmb3IgZGlmZmVyZW50aWFsIGV4cHJlc3Npb24gYmV0d2VlbiBuZWlnaGJvdXJob29kcyBlbnJpY2hlZCBpbiBjaXJyaG90aWMgY2VsbHMgYW5kIG5laWdoYm91cmhvb2RzIGVucmljaGVkCgo8IS0tIChOb3cgY29kZWQgaW4gYG1pbG9SXFJcdGVzdERpZmZFeHAuUmApIC0tPgoKPCEtLSBgYGB7cn0gLS0+CjwhLS0gLnBlcmZvcm1fY291bnRzX2RnZSA8LSBmdW5jdGlvbihleHBycy5kYXRhLCB0ZXN0Lm1vZGVsLCBnZW5lLm9mZnNldD1nZW5lLm9mZnNldCwgLS0+CjwhLS0gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtb2RlbC5jb250cmFzdHM9TlVMTCwgbi5jb2VmPU5VTEwpeyAtLT4KCjwhLS0gICAgIGkuZGdlIDwtIERHRUxpc3QoY291bnRzPWV4cHJzLmRhdGEsIC0tPgo8IS0tICAgICAgICAgICAgICAgICAgICAgIGxpYi5zaXplPWxvZyhjb2xTdW1zKGV4cHJzLmRhdGEpKSkgLS0+Cgo8IS0tICAgICBpZihpc1RSVUUoZ2VuZS5vZmZzZXQpKXsgLS0+CjwhLS0gICAgICAgICBuLmdlbmUgPC0gYXBwbHkoZXhwcnMuZGF0YSwgMiwgZnVuY3Rpb24oWCkgc3VtKFggPiAwKSkgLS0+CjwhLS0gICAgICAgICBpZihuY29sKHRlc3QubW9kZWwpID09IDIpeyAtLT4KPCEtLSAgICAgICAgICAgICB0ZXN0Lm1vZGVsIDwtIGNiaW5kKHRlc3QubW9kZWwsIG4uZ2VuZSkgLS0+CjwhLS0gICAgICAgICAgICAgY29sbmFtZXModGVzdC5tb2RlbCkgPC0gYyhjb2xuYW1lcyh0ZXN0Lm1vZGVsKVsxOjJdLCAiTkdlbmVzIikgLS0+CjwhLS0gICAgICAgICB9IGVsc2UgaWYgKG5jb2wodGVzdC5tb2RlbCkgPiAyKXsgLS0+CjwhLS0gICAgICAgICAgICAgdGVzdC5tb2RlbCA8LSBjYmluZCh0ZXN0Lm1vZGVsWywgMV0sIG4uZ2VuZSwgdGVzdC5tb2RlbFssIGMoMjpuY29sKHRlc3QubW9kZWwpKV0pIC0tPgo8IS0tICAgICAgICAgICAgIGNvbG5hbWVzKHRlc3QubW9kZWwpIDwtIGMoY29sbmFtZXModGVzdC5tb2RlbClbMV0sICJOR2VuZXMiLCBjb2xuYW1lcyh0ZXN0Lm1vZGVsWywgYygyOm5jb2wodGVzdC5tb2RlbCkpXSkpIC0tPgo8IS0tICAgICAgICAgfSBlbHNleyAtLT4KPCEtLSAgICAgICAgICAgICBpZihuY29sKHRlc3QubW9kZWwpIDwgMil7IC0tPgo8IS0tICAgICAgICAgICAgICAgICB3YXJuaW5nKCJPbmx5IG9uZSBjb2x1bW4gaW4gbW9kZWwgbWF0cml4IC0gbXVzdCBoYXZlIGF0IGxlYXN0IDIuIGdlbmUub2Zmc2V0IGZvcmNlZCB0byAgRkFMU0UiKSAtLT4KPCEtLSAgICAgICAgICAgICB9IC0tPgo8IS0tICAgICAgICAgfSAtLT4KPCEtLSAgICAgfSAtLT4KCjwhLS0gICAgIGkuZGdlIDwtIGVzdGltYXRlRGlzcChpLmRnZSwgdGVzdC5tb2RlbCkgLS0+CjwhLS0gICAgIGkuZml0IDwtIGdsbVFMRml0KGkuZGdlLCB0ZXN0Lm1vZGVsLCByb2J1c3Q9VFJVRSkgLS0+Cgo8IS0tICAgICBpZighaXMubnVsbChtb2RlbC5jb250cmFzdHMpKXsgLS0+CjwhLS0gICAgICAgICBtb2QuY29uc3RyYXN0IDwtIG1ha2VDb250cmFzdHMoY29udHJhc3RzPW1vZGVsLmNvbnRyYXN0cywgbGV2ZWxzPXRlc3QubW9kZWwpIC0tPgo8IS0tICAgICAgICAgaS5yZXMgPC0gYXMuZGF0YS5mcmFtZSh0b3BUYWdzKGdsbVFMRlRlc3QoaS5maXQsIGNvbnRyYXN0PW1vZC5jb25zdHJhc3QpLCAtLT4KPCEtLSAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzb3J0LmJ5PSdub25lJywgbj1JbmYpKSAtLT4KPCEtLSAgICAgfSBlbHNleyAtLT4KPCEtLSAgICAgICAgIGlmKGlzLm51bGwobi5jb2VmKSl7IC0tPgo8IS0tICAgICAgICAgICAgIG4uY29lZiA8LSBuY29sKHRlc3QubW9kZWwpIC0tPgo8IS0tICAgICAgICAgfSAtLT4KPCEtLSAgICAgICAgIGkucmVzIDwtIGFzLmRhdGEuZnJhbWUodG9wVGFncyhnbG1RTEZUZXN0KGkuZml0LCBjb2VmPW4uY29lZiksIHNvcnQuYnk9J25vbmUnLCBuPUluZikpIC0tPgo8IS0tICAgICB9IC0tPgo8IS0tICAgICByZXR1cm4oaS5yZXMpIC0tPgo8IS0tIH0gLS0+Cgo8IS0tIGBgYCAtLT4KCiMjIE5PVEU6IENvZGUgYmVsb3cgaGVyZSB3b24ndCB3b3JrIHVubGVzcyBgaHZnc2AgaXMgZGVmaW5lZAojIyMgRFJUOiBzdG9wcGluZyBydW4tdGhyb3VnaCBoZXJlClNob3VsZCBiZSBhYmxlIHRvIHJ1biBldmVyeXRoaW5nIGFib3ZlLgotLS0tCgpBZGQgbmhvb2QgZXhwcmVzc2lvbiB0byBzcGVlZC11cCBwbG90dGluZyBvZiBoZWF0bWFwcwoKYGBge3J9CmxpdmVyX21pbG8gPC0gY2FsY05ob29kRXhwcmVzc2lvbihsaXZlcl9taWxvLCBhc3NheSA9ICJsb2djb3VudHMiLCBzdWJzZXQucm93ID0gaHZncykKYGBgCgoKIyMgRW5kb3RoZWxpYQoKUmVidXR0YWwgZmlndXJlIHNob3djYXNpbmcgZ3JvdXBpbmcKCmBgYHtyLCBmaWcuaGVpZ2h0PTUsIGZpZy53aWR0aD0xNH0Kc2V0LnNlZWQoNDIpCm1pbG9fcmVzX2VuZG9ncm91cHMgPC0gZ3JvdXBOaG9vZHMobGl2ZXJfbWlsbywgbWlsb19yZXMsIG1heC5sZmMuZGVsdGEgPSAyLCBvdmVybGFwID0gMSkKCnAxIDwtIHBsb3ROaG9vZEdyb3VwcyhsaXZlcl9taWxvLCBtaWxvX3Jlc19lbmRvZ3JvdXBzLCAKICAgICAgICAgICAgICAgIHNpemVfcmFuZ2U9YygxLDMpKSAKCm1pbG9fcmVzX2VuZG9ncm91cHMgPC0gYW5ub3RhdGVOaG9vZHMobGl2ZXJfbWlsbywgbWlsb19yZXNfZW5kb2dyb3VwcywgJ2Fubm90YXRpb25fbGluZWFnZScpCgpwMiA8LSBwbG90REFiZWVzd2FybShtaWxvX3Jlc19lbmRvZ3JvdXBzLCBncm91cC5ieSA9ICdOaG9vZEdyb3VwJykgKwogIGZhY2V0X2dyaWQoYW5ub3RhdGlvbl9saW5lYWdlfi4sIHNjYWxlcz0iZnJlZSIsIHNwYWNlPSJmcmVlIikKCgojIyBQbG90IGV4cHJlc3Npb24gaW4gVCBjZWxsIG5laWdoYm91cmhvb2RzCm1hcmtlcnNfZGYgPC0gcmVhZF9jc3YoIn4vbW91bnQvZ2RyaXZlL21pbG8vU1RhYmxlM19SYW1hY2hhbmRyYW4uY3N2IikKdGNlbGxfbWFya2VyX2dlbmVzIDwtIAogIG1hcmtlcnNfZGYgJT4lCiAgZmlsdGVyKGNsdXN0ZXIgJWluJSBjKCJUY2VsbCIsICJJTEMiKSkgJT4lCiAgdG9wX24oMzAsIG15QVVDKSAlPiUKICBwdWxsKGdlbmUpCgpwMyA8LSBwbG90Tmhvb2RFeHByZXNzaW9uR3JvdXBzKGxpdmVyX21pbG8sIG1pbG9fcmVzX2VuZG9ncm91cHMsIGZlYXR1cmVzID0gdW5pcXVlKHRjZWxsX21hcmtlcl9nZW5lcyksIAogICAgICAgICAgICAgICAgICAgICAgICAgIHN1YnNldC5uaG9vZHMgPSBtaWxvX3Jlc19lbmRvZ3JvdXBzJE5ob29kR3JvdXAgJWluJSBjKCIzIiwiMTAiLCAiMTQiKSwKICAgICAgICAgICAgICAgICAgICAgICAgICBzY2FsZT1UUlVFLCBjbHVzdGVyX2ZlYXR1cmVzID0gVFJVRSxzaG93X3Jvd25hbWVzID0gVFJVRQogICAgICAgICAgICAgICAgICAgICAgICAgICkgKwogIHRoZW1lKHN0cmlwLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZT05MCkpCgpgYGAKYGBge3IsIGZpZy53aWR0aD0xNSwgZmlnLmhlaWdodD0xMH0KKCgocDEgKyB0aGVtZSgpKS8gKHAzICsgdGhlbWUoc3RyaXAudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplPTEwLCBhbmdsZT00NSkpKSkgKyAKICBwbG90X2xheW91dChoZWlnaHRzID0gYygxLjEsMSksIGd1aWRlcz0iY29sbGVjdCIKICAgICAgICAgICAgICApfCAKICAoCiAgICBwMiArIHRoZW1lX2J3KGJhc2Vfc2l6ZT0xNikgKyB0aGVtZShzdHJpcC50ZXh0LnkgPSBlbGVtZW50X3RleHQoYW5nbGU9MCkpCiAgICApKSArIAogIHBsb3RfbGF5b3V0KHdpZHRocyA9IGMoMS40LCAxKSkgKwogIHBsb3RfYW5ub3RhdGlvbih0YWdfbGV2ZWxzID0gYygiQSIsICJDIiwgIkIiKSApICsKICBnZ3NhdmUoIn4vbW91bnQvZ2RyaXZlL21pbG8vRmlndXJlcy9saXZlcl92Mi9SRmlnX2dyb3VwaW5nLnBkZiIsIHdpZHRoPTE1LCBoZWlnaHQgPSAxMikgKwogIGdnc2F2ZSgifi9tb3VudC9nZHJpdmUvbWlsby9GaWd1cmVzL2xpdmVyX3YyL1JGaWdfZ3JvdXBpbmcucG5nIiwgd2lkdGg9MTUsIGhlaWdodCA9IDEyKQpgYGAKCkdyb3VwIGVuZG90aGVsaWFsIGNlbGxzIGJ5IGxvZ0ZDIGFuZCBEQSByZXN1bHRzCgpgYGB7cn0KbWlsb19yZXNfZW5kb2dyb3VwcyRhbm5vdGF0aW9uX2luZGVwdGhbbWlsb19yZXNfZW5kb2dyb3VwcyRhbm5vdGF0aW9uX2luZGVwdGhfZnJhY3Rpb24gPCAwLjZdIDwtIE5BCm1pbG9fcmVzX2VuZG9ncm91cHMkYW5ub3RhdGlvbl9saW5lYWdlW21pbG9fcmVzX2VuZG9ncm91cHMkYW5ub3RhdGlvbl9pbmRlcHRoX2ZyYWN0aW9uIDwgMC42XSA8LSBOQQoKIyMgR3JvdXAgbmVpZ2hib3VyaG9vZHMgYnkgREEgb3V0Y29tZQptaWxvX3Jlc19lbmRvZ3JvdXBzJE5ob29kR3JvdXAgPC0gTkEKbWlsb19yZXNfZW5kb2dyb3VwcyROaG9vZEdyb3VwIDwtIGlmZWxzZSgobWlsb19yZXNfZW5kb2dyb3VwcyRhbm5vdGF0aW9uX2xpbmVhZ2UgPT0gIkVuZG90aGVsaWEiKSAmIChtaWxvX3Jlc19lbmRvZ3JvdXBzJFNwYXRpYWxGRFIgPCAwLjEpICYgKG1pbG9fcmVzX2VuZG9ncm91cHMkbG9nRkMgPCAtMi41KSwgIjU0IiwgbWlsb19yZXNfZW5kb2dyb3VwcyROaG9vZEdyb3VwKQptaWxvX3Jlc19lbmRvZ3JvdXBzJE5ob29kR3JvdXAgPC0gaWZlbHNlKChtaWxvX3Jlc19lbmRvZ3JvdXBzJGFubm90YXRpb25fbGluZWFnZSA9PSAiRW5kb3RoZWxpYSIpICYgKG1pbG9fcmVzX2VuZG9ncm91cHMkU3BhdGlhbEZEUiA8IDAuMSkgJiAobWlsb19yZXNfZW5kb2dyb3VwcyRsb2dGQyA+IDIuNSksICI3MCIsIG1pbG9fcmVzX2VuZG9ncm91cHMkTmhvb2RHcm91cCkKCgpsaXZlcl9taWxvMiA8LSBsaXZlcl9taWxvCnN1YnNldC5uaG9vZHMgPC0gc3RyX2RldGVjdChtaWxvX3JlcyRhbm5vdGF0aW9uX2luZGVwdGgsICJFbmRvIikKcmVkdWNlZERpbShsaXZlcl9taWxvMiwgIlVNQVAiKVtjb2xuYW1lcyhlbmRvX21pbG8pLF0gPC0gcmVkdWNlZERpbShlbmRvX21pbG8sICJVTUFQIikgCmVuZG9fZ3JfZ3JvdXBzIDwtIHBsb3ROaG9vZEdyb3VwcyhsaXZlcl9taWxvMiwgbWlsb19yZXNfZW5kb2dyb3Vwc1ttaWxvX3Jlc19lbmRvZ3JvdXBzJGFubm90YXRpb25fbGluZWFnZT09IkVuZG90aGVsaWEiLF0sIAogICAgICAgICAgICAgICAgc2hvd19ncm91cHMgPSBjKCI1NCIsICI3MCIpLAogICAgICAgICAgICAgICAgc2l6ZV9yYW5nZT1jKDEsNCksCiAgICAgICAgICAgICAgICBzdWJzZXQubmhvb2RzID0gbWlsb19yZXNfZW5kb2dyb3VwcyRhbm5vdGF0aW9uX2xpbmVhZ2U9PSJFbmRvdGhlbGlhIikgKwogIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcz1jKCI1NCI9YnJld2VyLnBhbCg0LCAiU3BlY3RyYWwiKVsyXSwgIjcwIj1icmV3ZXIucGFsKDQsICJTcGVjdHJhbCIpWzNdKSwgCiAgICAgICAgICAgICAgICAgICAgbGFiZWxzPWMoIjU0Ij0iVW5pbmp1cmVkIGdyb3VwIiwgJzcwJz0gIkNpcnJob3RpYyBncm91cCIpLAogICAgICAgICAgICAgICAgICAgIG5hLnZhbHVlPSJ3aGl0ZSIsCiAgICAgICAgICAgICAgICAgICAgbmFtZSA9ICJOaG9vZCBncm91cCIKICAgICAgICAgICAgICAgICAgICApICsKICB0aGVtZShsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplPTIwKSwgbGVnZW5kLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemU9MjIpKQpgYGAKCmBgYHtyLCBmaWcud2lkdGg9MTgsIGZpZy5oZWlnaHQ9NX0KZmlnNF9icmlnaHQxIDwtICgoZW5kb191bWFwICsgZW5kb19ncikgKyAKICBwbG90X2xheW91dCh3aWR0aHMgPSBjKDEsMiksIGd1aWRlcz0iY29sbGVjdCIKICAgICAgICAgICAgICAgICkpICYKICB0aGVtZShsZWdlbmQuYm94ID0gImhvcml6b250YWwiLCBsZWdlbmQucG9zaXRpb24gPSAidG9wIiwgbGVnZW5kLmRpcmVjdGlvbiA9ICJ2ZXJ0aWNhbCIpCmZpZzRfYnJpZ2h0MQpgYGAKCgpDYWxjdWxhdGUgbWFya2VyIGdlbmVzIGJldHdlZW4gdGhlIHR3byBncm91cHMKYGBge3J9Cm1pdG9fZ2VuZXMgPC0gc3RyX2RldGVjdChodmdzLCAiXk1ULSIpCm1hcmtlcnNfZGYgPC0gZmluZE5ob29kR3JvdXBNYXJrZXJzKGxpdmVyX21pbG8sIGRhLnJlcyA9IG1pbG9fcmVzX2VuZG9ncm91cHMsIGFzc2F5PSJjb3VudHMiLAogICAgICAgICAgICAgICAgICAgICAgc3Vic2V0Lm5ob29kcyA9IChtaWxvX3Jlc19lbmRvZ3JvdXBzJE5ob29kR3JvdXAgJWluJSBjKCI1NCIsICI3MCIpKSwKICAgICAgICAgICAgICAgICAgICAgIHN1YnNldC5ncm91cHMgPSBjKCI1NCIsICI3MCIpLAogICAgICAgICAgICAgICAgICAgICAgc3Vic2V0LnJvdyA9IGh2Z3NbIW1pdG9fZ2VuZXNdLAogICAgICAgICAgICAgICAgICAgICAgYWdncmVnYXRlLnNhbXBsZXMgPSBUUlVFLCBzYW1wbGVfY29sID0gImRhdGFzZXQiCiAgICAgICAgICAgICAgICAgICAgICApCgptaWxvX3Jlc19lbmRvZ3JvdXBzW21pbG9fcmVzX2VuZG9ncm91cHMkTmhvb2RHcm91cCAlaW4lIGMoIjU0IiwgIjcwIiksXQoKY29sbmFtZXMobWFya2Vyc19kZikgPC0gc3RyX3JlcGxhY2UoY29sbmFtZXMobWFya2Vyc19kZiksICI3MCIsICJjaXJyIikKY29sbmFtZXMobWFya2Vyc19kZikgPC0gc3RyX3JlcGxhY2UoY29sbmFtZXMobWFya2Vyc19kZiksICI1NCIsICJ1bmluaiIpCmBgYAoKIyMjIyBWaXN1YWxpemUgYXMgdm9sY2FubyAKCmBgYHtyLCBmaWcuaGVpZ2h0PTYsIGZpZy53aWR0aD0xMCwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KCmhpZ2hsaWdodF9nZW5lcyA8LSBjKCJQTFZBUCIsICJWV0ExIiwgIkFDS1IxIiwgIklMMzIiLAogICAgICAgICAgICAgICAgICAgICAiQ0xFQzRHIiwgIkNMRUM0TSIsICJGQ04yIiwgIkZDTjMiLAogICAgICAgICAgICAgICAgICAgICAiTEVGMSIpCgptYXJrZXIuZGYgPC0gbWFya2Vyc19kZgptYXJrZXIuZGYgJT4lCiAgbXV0YXRlKGxhYmVsPWlmZWxzZShHZW5lSUQgJWluJSBoaWdobGlnaHRfZ2VuZXMsIEdlbmVJRCwgTkEpKSAlPiUKICBnZ3Bsb3QoYWVzKGxvZ0ZDX2NpcnIsIC1sb2cxMChhZGouUC5WYWxfY2lyciksIAogICAgICAgICAgICAgIyBjb2xvcj1oaWdobGlnaHQKICAgICAgICAgICAgICkpICsgCiAgZ2VvbV9wb2ludCgpICsKICBnZW9tX3RleHQoYWVzKGxhYmVsPWxhYmVsKSwgY29sb3I9InJlZCIpICsKICB4bGFiKCJsb2dGQyIpICsgeWxhYigiLSBsb2cxMChBZGouIFAgdmFsdWUpIikgKwogIHRoZW1lX2J3KGJhc2Vfc2l6ZSA9IDIyKQogIApgYGAKCgojIyMjIFZpc3VhbGl6ZSBhcyBoZWF0bWFwIAooZ2VuZSBleHByZXNzaW9uIHZhbHVlcyBhcmUgc2NhbGVkIGJldHdlZW4gMCBhbmQgMSBmb3IgZWFjaCBnZW5lKQoKYGBge3IsIGZpZy5oZWlnaHQ9MTAsIGZpZy53aWR0aD0xMiwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KbWFya2VyX2dlbmVzIDwtIG1hcmtlci5kZiAlPiUKICBkcGx5cjo6ZmlsdGVyKGFkai5QLlZhbF9jaXJyIDwgMC4wNSkgJT4lCiAgcHVsbChHZW5lSUQpCgpmaWc0X2JicmlnaHQgPC0KICBwbG90Tmhvb2RFeHByZXNzaW9uREEobGl2ZXJfbWlsbywgbWlsb19yZXNfZW5kb2dyb3VwcywgYyhtYXJrZXJfZ2VuZXMpLCBjbHVzdGVyX2ZlYXR1cmVzID0gVFJVRSwgYXNzYXkgPSAiY291bnRzIiwKICAgICAgICAgICAgICAgICAgICAgIGFscGhhID0gMC4xLAogICAgICAgICAgICAgICAgICAgICAgc2NhbGVfdG9fMSA9IFRSVUUsCiAgICAgICAgICAgICAgICAgICAgICBzdWJzZXQubmhvb2RzID0gIG1pbG9fcmVzX2VuZG9ncm91cHMkTmhvb2RHcm91cCAlaW4lIGMoIjU0IiwgIjcwIiksCiAgICAgICAgICAgICAgICAgICAgICAjIGdyaWQuc3BhY2UgPSAiZnJlZSIsCiAgICAgICAgICAgICAgICAgICAgICBoaWdobGlnaHRfZmVhdHVyZXMgPSBoaWdobGlnaHRfZ2VuZXMsIHNob3dfcm93bmFtZXMgPSBGQUxTRQogICAgICAgICAgICAgICAgICAgICAgKSArCiAgeWxhYigiREUgZ2VuZXMiKSsKICAjIGZhY2V0X2dyaWQoLn5OaG9vZEdyb3VwLCBzY2FsZXM9ImZyZWUiLCBzcGFjZT0iZnJlZSIpCiAgIHRoZW1lKGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemU9MjIpLCBsZWdlbmQudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZT0yNCkpICsKICBwbG90X2xheW91dChoZWlnaHRzID0gYygxLDEwKSkgJiB0aGVtZShsZWdlbmQubWFyZ2luID0gbWFyZ2luKDAsMCwwLDYwKSwgbGVnZW5kLmJhY2tncm91bmQgPSBlbGVtZW50X2JsYW5rKCkpCgogIApwbDMgPC0gZmlnNF9iYnJpZ2h0JGRhdGEgJT4lCiAgZ2dwbG90KGFlcyhsb2dGQ19yYW5rLCAxLGZpbGw9bG9nRkMpKSArCiAgZ2VvbV90aWxlKCkgKwogICAgICB0aGVtZV9jbGFzc2ljKGJhc2Vfc2l6ZT0xNikgKwogICAgeWxhYigiIikgKwogIHNjYWxlX2ZpbGxfZ3JhZGllbnQyKG5hbWU9IkRBIGxvZ0ZDIikgKwogICAgIyBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXM9YygiNTQiPWJyZXdlci5wYWwoNCwgIlNwZWN0cmFsIilbMl0sICI3MCI9YnJld2VyLnBhbCg0LCAiU3BlY3RyYWwiKVszXSksIAogICAgIyAgICAgICAgICAgICAgICAgbGFiZWxzPWMoIjU0Ij0iVW5pbmp1cmVkIGdyb3VwIiwgJzcwJz0gIkNpcnJob3RpYyBncm91cCIpLAogICAgIyAgICAgICAgICAgICAgICAgbmEudmFsdWU9IndoaXRlIiwKICAgICMgICAgICAgICAgICAgICAgIG5hbWUgPSAiTmhvb2QgZ3JvdXAiCiAgICAjICAgICAgICAgICAgICAgICApICsKICAgIHNjYWxlX3hfY29udGludW91cyhleHBhbmQgPSBjKDAuMDEsIDApKSArCiAgICB0aGVtZShheGlzLnRleHQgPSBlbGVtZW50X2JsYW5rKCksIGF4aXMudGlja3MgPSBlbGVtZW50X2JsYW5rKCksIGF4aXMubGluZSA9IGVsZW1lbnRfYmxhbmsoKSwgCiAgICAgICAgICBheGlzLnRpdGxlID0gZWxlbWVudF9ibGFuaygpKQoKZmlnNF9iYnJpZ2h0IDwtIHBsMyAvIGZpZzRfYmJyaWdodCAgKwogIHBsb3RfbGF5b3V0KGhlaWdodHMgPSBjKDEsMjApKQoKZmlnNF9iYnJpZ2h0CmBgYAoKIyMjIEdPIHRlcm0gYW5hbHlzaXMKCmBgYHtyLCBlY2hvPUZBTFNFLCB3YXJuaW5nPUZBTFNFLCBtZXNzYWdlPUZBTFNFfQojIEJpb2NNYW5hZ2VyOjppbnN0YWxsKCdjbHVzdGVyUHJvZmlsZXInKQojIEJpb2NNYW5hZ2VyOjppbnN0YWxsKCdtc2lnZGJyJykKbGlicmFyeShjbHVzdGVyUHJvZmlsZXIpCmxpYnJhcnkobXNpZ2RicikKCm1fZGYgPC0gbXNpZ2RicihzcGVjaWVzID0gIkhvbW8gc2FwaWVucyIpCm1fdDJnIDwtIG1zaWdkYnIoc3BlY2llcyA9ICJIb21vIHNhcGllbnMiLCBjYXRlZ29yeSA9ICJDNSIsIHN1YmNhdGVnb3J5ID0gIkJQIikgICU+JSAKICBkcGx5cjo6c2VsZWN0KGdzX25hbWUsIGdlbmVfc3ltYm9sKQpgYGAKCmBgYHtyLCBlY2hvPUZBTFNFLCB3YXJuaW5nPUZBTFNFLCBtZXNzYWdlPUZBTFNFfQptYXJrZXJfZ2VuZXNfdXAgPC0gbWFya2VyLmRmICU+JQogIGRwbHlyOjpmaWx0ZXIoYWRqLlAuVmFsX2NpcnIgPCAwLjA1ICYgbG9nRkNfY2lyciA+IDAuNSkgJT4lCiAgcHVsbChHZW5lSUQpIAoKbWFya2VyX2dlbmVzX2Rvd24gPC0gbWFya2VyLmRmICU+JQogIGRwbHlyOjpmaWx0ZXIoYWRqLlAuVmFsX2NpcnIgPCAwLjA1ICYgbG9nRkNfdW5pbmogPiAwLjUpICU+JQogIHB1bGwoR2VuZUlEKQoKZW1fdXAgPC0gZW5yaWNoZXIobWFya2VyX2dlbmVzX3VwLCBURVJNMkdFTkU9bV90MmcsIHBBZGp1c3RNZXRob2QgPSAiZmRyIiwgCiAgICAgICAgICAgICAgICAgIHVuaXZlcnNlID0gaHZncwogICAgICAgICAgICAgICAgICApCmVtX2Rvd24gPC0gZW5yaWNoZXIobWFya2VyX2dlbmVzX2Rvd24sIFRFUk0yR0VORT1tX3QyZywgcEFkanVzdE1ldGhvZCA9ICJmZHIiLCAKICAgICAgICAgICAgICAgICAgICB1bml2ZXJzZSA9IHJvd25hbWVzKGxpdmVyX21pbG8pCiAgICAgICAgICAgICAgICAgICAgKQoKZW1fcmVzX3VwIDwtIGVtX3VwQHJlc3VsdFtlbV91cEByZXN1bHQkcXZhbHVlIDwgMC4xLF0gJT4lCiAgZHBseXI6OnNlbGVjdCgtIGMoRGVzY3JpcHRpb24pKQplbV9yZXNfZG93biA8LSBlbV9kb3duQHJlc3VsdFtlbV9kb3duQHJlc3VsdCRxdmFsdWUgPCAwLjEsXSAlPiUKICBkcGx5cjo6c2VsZWN0KC0gYyhEZXNjcmlwdGlvbikpCmBgYAoKYGBge3IsIGZpZy5oZWlnaHQ9OCwgZmlnLndpZHRoPTE1LCB3YXJuaW5nPUZBTFNFLCBtZXNzYWdlPUZBTFNFfQpnb19lbmRvX3VwIDwtIGVtX3Jlc191cCAlPiUKICB0b3BfbigzMCwgLWxvZzEwKHF2YWx1ZSkpICU+JQogICBtdXRhdGUoSUQ9aWZlbHNlKElEPT0nR09fQU5USUdFTl9QUk9DRVNTSU5HX0FORF9QUkVTRU5UQVRJT05fT0ZfUEVQVElERV9PUl9QT0xZU0FDQ0hBUklERV9BTlRJR0VOX1ZJQV9NSENfQ0xBU1NfSUknLCAiR09fQU5USUdFTl9QUkVTRU5UQVRJT05fVklBX01IQ19DTEFTU19JSSIsIElEKSkgJT4lCiAgbXV0YXRlKFRlcm09ZmFjdG9yKElELCBsZXZlbHM9cmV2KHVuaXF1ZShJRCkpKSkgJT4lCiAgZ2dwbG90KGFlcyhUZXJtLCAtbG9nMTAocXZhbHVlKSkpICsKICBnZW9tX3BvaW50KCkgKwogIGNvb3JkX2ZsaXAoKSArCiAgeGxhYigiR08gQmlvbG9naWNhbCBGdW5jdGlvbiIpICsgeWxhYigiLWxvZzEwKEFkai4gcC12YWx1ZSkiKSArCiAgdGhlbWVfYncoYmFzZV9zaXplPTE4KSArCiAgZ2d0aXRsZSgiQ2lycmhvdGljIGVuZG90aGVsaWEiKQoKZ29fZW5kb19kb3duIDwtIGVtX3Jlc19kb3duICU+JQogIHRvcF9uKDMwLCAtbG9nMTAocXZhbHVlKSkgJT4lCiAgbXV0YXRlKElEPWlmZWxzZShJRD09J0dPX0FOVElHRU5fUFJPQ0VTU0lOR19BTkRfUFJFU0VOVEFUSU9OX09GX1BFUFRJREVfT1JfUE9MWVNBQ0NIQVJJREVfQU5USUdFTl9WSUFfTUhDX0NMQVNTX0lJJywgIkdPX0FOVElHRU5fUFJFU0VOVEFUSU9OX1ZJQV9NSENfQ0xBU1NfSUkiLCBJRCkpICU+JQogIG11dGF0ZShUZXJtPWZhY3RvcihJRCwgbGV2ZWxzPXJldih1bmlxdWUoSUQpKSkpICU+JQogIGdncGxvdChhZXMoVGVybSwgLWxvZzEwKHF2YWx1ZSkpKSArCiAgZ2VvbV9wb2ludCgpICsKICBjb29yZF9mbGlwKCkgKwogIHhsYWIoIkdPIEJpb2xvZ2ljYWwgRnVuY3Rpb24iKSArIHlsYWIoIi1sb2cxMChBZGouIHAtdmFsdWUpIikgKwogIHRoZW1lX2J3KGJhc2Vfc2l6ZT0xOCkgKwogIGdndGl0bGUoIlVuaW5qdXJlZCBlbmRvdGhlbGlhIikKCmdvX2VuZG9fdXAKZ29fZW5kb19kb3duCmBgYAoKCmBgYHtyfQplbV9yZXNfdXAKZW1fcmVzX2Rvd24KYGBgCgojIyBDaG9sYW5naW9jeXRlcwoKYGBge3J9CnNldC5zZWVkKDQyKQptaWxvX3Jlc19jaG9sZ3JvdXBzIDwtIGdyb3VwTmhvb2RzKGxpdmVyX21pbG8sIG1pbG9fcmVzLCBtYXgubGZjLmRlbHRhID0gMC41LCBvdmVybGFwID0gMSkKCiMjIEdyb3VwIG5laWdoYm91cmhvb2RzIGJ5IERBIG91dGNvbWUKbWlsb19yZXNfY2hvbGdyb3VwcyROaG9vZEdyb3VwIDwtIE5BCm1pbG9fcmVzX2Nob2xncm91cHMkTmhvb2RHcm91cCA8LSBpZmVsc2UoKG1pbG9fcmVzX2Nob2xncm91cHMkYW5ub3RhdGlvbl9saW5lYWdlID09ICJDaG9sYW5naW9jeXRlcyIpICYgKG1pbG9fcmVzX2Nob2xncm91cHMkU3BhdGlhbEZEUiA8IDAuMSkgJiAobWlsb19yZXNfY2hvbGdyb3VwcyRsb2dGQyA8IC0yLjUpLCAiMzgiLCBtaWxvX3Jlc19jaG9sZ3JvdXBzJE5ob29kR3JvdXApCm1pbG9fcmVzX2Nob2xncm91cHMkTmhvb2RHcm91cCA8LSBpZmVsc2UoKG1pbG9fcmVzX2Nob2xncm91cHMkYW5ub3RhdGlvbl9saW5lYWdlID09ICJDaG9sYW5naW9jeXRlcyIpICYgKG1pbG9fcmVzX2Nob2xncm91cHMkU3BhdGlhbEZEUiA8IDAuMSkgJiAobWlsb19yZXNfY2hvbGdyb3VwcyRsb2dGQyA+IDIuNSksICI0OSIsIG1pbG9fcmVzX2Nob2xncm91cHMkTmhvb2RHcm91cCkKCmxpdmVyX21pbG8yIDwtIGxpdmVyX21pbG8Kc3Vic2V0Lm5ob29kcyA8LSBzdHJfZGV0ZWN0KG1pbG9fcmVzJGFubm90YXRpb25faW5kZXB0aCwgIkNob2wiKQpyZWR1Y2VkRGltKGxpdmVyX21pbG8yLCAiVU1BUCIpW2NvbG5hbWVzKGNob2xfbWlsbyksXSA8LSByZWR1Y2VkRGltKGNob2xfbWlsbywgIlVNQVAiKSAKcGxvdE5ob29kR3JvdXBzKGxpdmVyX21pbG8yLCBtaWxvX3Jlc19jaG9sZ3JvdXBzW21pbG9fcmVzX2Nob2xncm91cHMkYW5ub3RhdGlvbl9saW5lYWdlPT0iQ2hvbGFuZ2lvY3l0ZXMiLF0sIAogICAgICAgICAgICAgICAgc2hvd19ncm91cHMgPSBjKCI0OSIsIjM4IiksCiAgICAgICAgICAgICAgICBzdWJzZXQubmhvb2RzID0gIG1pbG9fcmVzX2Nob2xncm91cHMkYW5ub3RhdGlvbl9saW5lYWdlID09IkNob2xhbmdpb2N5dGVzIikKCmBgYAoKQ2FsY3VsYXRlIG1hcmtlciBnZW5lcyBiZXR3ZWVuIHRoZSB0d28gZ3JvdXBzCmBgYHtyfQojIyBGaWx0ZXIgZ2VuZXMgZXhwcmVzc2VkIGluIGNob2xhbmdpb2N5dGVzCiMgY2hvbF9odmdzIDwtIGh2Z3NbKGNvdW50cyhjaG9sX21pbG8pW2h2Z3MsXSA+IDApICU+JSB7cm93U3VtcyguKS9uY29sKGNob2xfbWlsbyl9ID4gMC4wMV0KbWl0b19nZW5lcyA8LSBzdHJfZGV0ZWN0KGh2Z3MsICJeTVQtIikKCm1hcmtlcnNfZGYgPC0gZmluZE5ob29kR3JvdXBNYXJrZXJzKGxpdmVyX21pbG8sIGRhLnJlcyA9IG1pbG9fcmVzX2Nob2xncm91cHMsIGFzc2F5PSJjb3VudHMiLAogICAgICAgICAgICAgICAgICAgICAgc3Vic2V0Lm5ob29kcyA9IG1pbG9fcmVzX2Nob2xncm91cHMkTmhvb2RHcm91cCAlaW4lYygiNDkiLCIzOCIpLAogICAgICAgICAgICAgICAgICAgICAgc3Vic2V0Lmdyb3VwcyA9IGMoIjQ5IiwiMzgiKSwKICAgICAgICAgICAgICAgICAgICAgIHN1YnNldC5yb3cgPSBodmdzWyFtaXRvX2dlbmVzXSwKICAgICAgICAgICAgICAgICAgICAgIGFnZ3JlZ2F0ZS5zYW1wbGVzID0gVFJVRSwgc2FtcGxlX2NvbCA9ICJkYXRhc2V0IgogICAgICAgICAgICAgICAgICAgICAgKQoKbWFya2Vyc19kZiAKCm1pbG9fcmVzX2Nob2xncm91cHNbbWlsb19yZXNfY2hvbGdyb3VwcyROaG9vZEdyb3VwICVpbiVjKCI0OSIsIjM4IiksXQpgYGAKCiMjIyMgVmlzdWFsaXplIGFzIHZvbGNhbm8gCgpgYGB7ciwgZmlnLmhlaWdodD02LCBmaWcud2lkdGg9MTAsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9Cm1hcmtlci5kZi5jaG9sIDwtIG1hcmtlcnNfZGYKCnZvbGNhbm9fY2hvbCA8LQogIG1hcmtlci5kZi5jaG9sICU+JQogIG11dGF0ZSh1cD1pZmVsc2UobG9nRkNfNDkgPiAwLCAidXAiLCAiZG93biIpKSAlPiUKICBncm91cF9ieSh1cCkgJT4lCiAgbXV0YXRlKGxhYmVsPWlmZWxzZShyYW5rKGFkai5QLlZhbF80OSkgPCAxNSwgR2VuZUlELCBOQSkpICU+JQogICMgbXV0YXRlKGxhYmVsPWlmZWxzZSgoYWRqLlAuVmFsXzQ5IDwgMC4wNSAmIGxvZ0ZDXzQ5IDwgLTMpIHwgKGFkai5QLlZhbF80OSA8IDAuMDUgJiBsb2dGQ180OSA+IDApLCBHZW5lSUQsIE5BKSkgJT4lCiAgZ2dwbG90KGFlcyhsb2dGQ180OSwgLWxvZzEwKGFkai5QLlZhbF80OSksIAogICAgICAgICAgICAgIyBjb2xvcj1oaWdobGlnaHQKICAgICAgICAgICAgICkpICsgCiAgZ2VvbV9wb2ludChzaXplPTAuOCwgYWxwaGE9MC42KSArCiAgZ2dyZXBlbDo6Z2VvbV90ZXh0X3JlcGVsKGFlcyhsYWJlbD1sYWJlbCksIHNlZ21lbnQuYWxwaGEgPSAwLjIpICsKICB4bGFiKCJsb2dGQyIpICsgeWxhYigiLSBsb2cxMChBZGouIFAgdmFsdWUpIikgKwogIHRoZW1lX2J3KGJhc2Vfc2l6ZSA9IDIyKQoKdm9sY2Fub19jaG9sICAKICAKYGBgCgoKCiMjIyBHTyB0ZXJtIGFuYWx5c2lzCgpgYGB7ciwgZWNobz1GQUxTRSwgd2FybmluZz1GQUxTRSwgbWVzc2FnZT1GQUxTRX0KbWFya2VyX2dlbmVzX2Nob2wgPC0gbWFya2VyLmRmLmNob2wgJT4lCiAgZHBseXI6OmZpbHRlcihhZGouUC5WYWxfNDkgPCAwLjA1ICYgbG9nRkNfNDkgPiAwKSAlPiUKICBwdWxsKEdlbmVJRCkKCmVtX3VwX2Nob2wgPC0gZW5yaWNoZXIobWFya2VyX2dlbmVzX2Nob2wsIFRFUk0yR0VORT1tX3QyZywgcEFkanVzdE1ldGhvZCA9ICJmZHIiLCAKICAgICAgICAgICAgICAgICAgdW5pdmVyc2UgPSByb3duYW1lcyhsaXZlcl9taWxvKQogICAgICAgICAgICAgICAgICApCgplbV9yZXNfdXBfY2hvbCA8LSBlbV91cF9jaG9sQHJlc3VsdFtlbV91cF9jaG9sQHJlc3VsdCRxdmFsdWUgPCAwLjEsXSAlPiUKICBkcGx5cjo6c2VsZWN0KC0gYyhEZXNjcmlwdGlvbikpCmBgYAoKYGBge3IsIGZpZy5oZWlnaHQ9OCwgZmlnLndpZHRoPTE1LCB3YXJuaW5nPUZBTFNFLCBtZXNzYWdlPUZBTFNFfQpnb19jaG9sX3VwIDwtIGVtX3Jlc191cF9jaG9sICU+JQogIHRvcF9uKDIwLCAtbG9nMTAocXZhbHVlKSkgJT4lCiAgbXV0YXRlKFRlcm09ZmFjdG9yKElELCBsZXZlbHM9cmV2KHVuaXF1ZShJRCkpKSkgJT4lCiAgZ2dwbG90KGFlcyhUZXJtLCAtbG9nMTAocXZhbHVlKSkpICsKICBnZW9tX3BvaW50KCkgKwogIGNvb3JkX2ZsaXAoKSArCiAgeGxhYigiR08gQmlvbG9naWNhbCBGdW5jdGlvbiIpICsgeWxhYigiLWxvZzEwKEFkai4gcC12YWx1ZSkiKSArCiAgdGhlbWVfYncoYmFzZV9zaXplPTE4KSArCiAgZ2d0aXRsZSgiQ2lycmhvdGljIGNob2xhbmdpb2N5dGVzIikKCmdvX2Nob2xfdXAKYGBgCgpgYGB7cn0KZW1fcmVzX3VwX2Nob2wKYGBgCmBgYHtyLCBlY2hvPUZBTFNFLCB3YXJuaW5nPUZBTFNFLCBtZXNzYWdlPUZBTFNFfQptYXJrZXJfZ2VuZXNfY2hvbF9kb3duIDwtIG1hcmtlci5kZi5jaG9sICU+JQogIGRwbHlyOjpmaWx0ZXIoYWRqLlAuVmFsXzQ5IDwgMC4wNSAmIGxvZ0ZDXzQ5IDwgMCkgJT4lCiAgcHVsbChHZW5lSUQpCgplbV9kb3duX2Nob2wgPC0gZW5yaWNoZXIobWFya2VyX2dlbmVzX2Nob2xfZG93biwgVEVSTTJHRU5FPW1fdDJnLCBwQWRqdXN0TWV0aG9kID0gImZkciIsIAogICAgICAgICAgICAgICAgICB1bml2ZXJzZSA9IHJvd25hbWVzKGxpdmVyX21pbG8pCiAgICAgICAgICAgICAgICAgICkKCmVtX3Jlc19kb3duX2Nob2wgPC0gZW1fZG93bl9jaG9sQHJlc3VsdFtlbV9kb3duX2Nob2xAcmVzdWx0JHF2YWx1ZSA8IDAuMSxdICU+JQogIGRwbHlyOjpzZWxlY3QoLSBjKERlc2NyaXB0aW9uKSkKYGBgCgoKLS0tCgpBc3NlbWJsZSBmaWd1cmUKYGBge3IsIGZpZy5oZWlnaHQ9MjUsIGZpZy53aWR0aD0xOX0KZmlnNF9ib3R0b20gPC0gKChmaWc0X2JsZWZ0ICsgcGxvdF9sYXlvdXQoKSkgfAogICAgICAoKGZpZzRfYnJpZ2h0MSArIHBsb3RfbGF5b3V0KHRhZ19sZXZlbCA9ICdrZWVwJykpIC8gKGZpZzRfYmJyaWdodCArIHBsb3RfbGF5b3V0KCkpKSArCiAgICAgIHBsb3RfbGF5b3V0KGhlaWdodHMgPSBjKDEsMS42KSkKICAgKSArCiAgcGxvdF9sYXlvdXQod2lkdGhzPWMoMSwxLjQpKQoKKGZpZzRfdG9wIC8gZmlnNF9ib3R0b20pICsKICBwbG90X2xheW91dChoZWlnaHRzPWMoMSwxLjgpKSAgKwogIGdnc2F2ZSgifi9tb3VudC9nZHJpdmUvbWlsby9GaWd1cmVzL2xpdmVyX3YyL2ZpZzRfcmF3LnBkZiIsIGhlaWdodCA9IDI2LCB3aWR0aCA9IDI0LCB1c2VEaW5nYmF0cz1GQUxTRSkgCiAgIyBnZ3NhdmUoIn4vbW91bnQvZ2RyaXZlL21pbG8vRmlndXJlcy9saXZlcl92Mi9maWc0X3Jhdy5wbmciLCBoZWlnaHQgPSAyNiwgd2lkdGggPSAyNCwgdXNlRGluZ2JhdHM9RkFMU0UpCiAgIyBnZ3NhdmUoIn4vbWlsby9tcy9maWd1cmVzL2ZpZ3MvZmlndXJlNS5wZGYiLCBoZWlnaHQgPSAyNiwgd2lkdGggPSAyMiwgdXNlRGluZ2JhdHM9RkFMU0UpCmBgYAoKQXNzZW1ibGUgc3VwcGxlbWVudGFyeSBmaWd1cmUKCmBgYHtyLCBmaWcud2lkdGg9MjUsIGZpZy5oZWlnaHQ9N30KcDEgPC0gcGxvdF9ncmlkKCBnb19lbmRvX3VwKyB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYXhpcy50aXRsZS54ID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMSkpLCAKICAgICAgICAgICAgICAgICBnb19lbmRvX2Rvd24rIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAxKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGF4aXMudGl0bGUueCA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDEpKSwgCiAgICAgICAgICAgICAgICAgbGFiZWxfc2l6ZSA9IDE4LAogICAgICAgICAgICAgICAgIG5jb2w9MSwKICAgICAgICAgICAgICAgICByZWxfaGVpZ2h0cyA9IGMoMiwyKSwKICAgICAgICAgICAgICAgIGxhYmVscyA9IGMoIkEiLCAiQiIsIkMiKSkKCnAxCgpjaG9sX2VtYiA8LSAoY2hvbF91bWFwICsgY2hvbF9nciApICsgCiAgcGxvdF9sYXlvdXQod2lkdGhzID0gYygxLDIpLCAKICAgICAgICAgICAgICAgIGd1aWRlcyA9ICJjb2xsZWN0IgogICAgICAgICAgICAgICAgKQoKYGBgCgpgYGB7ciwgZmlnLmhlaWdodD0xMCwgZmlnLndpZHRoPTh9CnBsb3RfZ3JpZCgKICBnb19lbmRvX3VwKyB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMSksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYXhpcy50aXRsZS54ID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMSkpLCAKICAgICAgICAgICAgICAgICBnb19lbmRvX2Rvd24rIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAxKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGF4aXMudGl0bGUueCA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDEpKSwgCiAgICAgICAgICAgICAgICAgbGFiZWxfc2l6ZSA9IDE4LAogICAgICAgICAgICAgICAgIG5jb2w9MSwKICAgICAgICAgICAgICAgICByZWxfaGVpZ2h0cyA9IGMoMiwyKSwgcmVsX3dpZHRocyA9IGMoMiwyKSwKICAgICAgICAgICAgICAgIGxhYmVscyA9IGMoIkEiLCAiQiIpCiAgKSArCiAgZ2dzYXZlKCJ+L21vdW50L2dkcml2ZS9taWxvL0ZpZ3VyZXMvbGl2ZXJfdjIvc3VwcGxfZmlnX2VuZG8ucGRmIiwgaGVpZ2h0ID0gMTIsIHdpZHRoPTEyKSArCiAgZ2dzYXZlKCJ+L21vdW50L2dkcml2ZS9taWxvL0ZpZ3VyZXMvbGl2ZXJfdjIvc3VwcGxfZmlnX2VuZG8ucG5nIiwgaGVpZ2h0ID0gMTIsIHdpZHRoPTEyKQoKCmBgYApgYGB7ciwgZmlnLmhlaWdodD0xMCwgZmlnLndpZHRoPTh9CnBsb3RfZ3JpZChwbG90X2dyaWQoY2hvbF91bWFwLCBjaG9sX2dyLCB2b2xjYW5vX2Nob2wsIG5yb3c9MSxyZWxfd2lkdGhzID0gYygxLDIsMiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgbGFiZWxfc2l6ZSA9IDE4LAogICAgICAgICAgICAgICAgbGFiZWxzID0gYygiQSIsIkIiLCJDIikpLAogICAgICAgICAgICAgICAgZ29fY2hvbF91cCArIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAxKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBheGlzLnRpdGxlLnggPSBlbGVtZW50X3RleHQoaGp1c3QgPSAxKSksIAogICAgICAgICAgICAgICAgbmNvbD0xLAogICAgICAgICAgICAgICAgcmVsX2hlaWdodHMgPSBjKDEsMSksCiAgICAgICAgICAgICAgICAgbGFiZWxfc2l6ZSA9IDE4LAogICAgICAgICAgICAgICAgbGFiZWxzPWMoIiIsJ0QnKSkgKwogICBnZ3NhdmUoIn4vbW91bnQvZ2RyaXZlL21pbG8vRmlndXJlcy9saXZlcl92Mi9zdXBwbF9maWc3LnBkZiIsIGhlaWdodCA9IDEzLCB3aWR0aD0xNCkgKwogIGdnc2F2ZSgifi9tb3VudC9nZHJpdmUvbWlsby9GaWd1cmVzL2xpdmVyX3YyL3N1cHBsX2ZpZzcucG5nIiwgaGVpZ2h0ID0gMTMsIHdpZHRoPTE0KSAKYGBgCg==